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 2016/01/05 07:05:46 UTC

[1/3] mina-sshd git commit: [SSHD-620] Add support for 'hostbased' authentication

Repository: mina-sshd
Updated Branches:
  refs/heads/master cbff09df7 -> 18335089d


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/StaticHostBasedAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/StaticHostBasedAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/StaticHostBasedAuthenticator.java
new file mode 100644
index 0000000..6792c51
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/StaticHostBasedAuthenticator.java
@@ -0,0 +1,72 @@
+/*
+ * 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.server.auth.hostbased;
+
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class StaticHostBasedAuthenticator extends AbstractLoggingBean implements HostBasedAuthenticator {
+    private final boolean acceptance;
+
+    public StaticHostBasedAuthenticator(boolean acceptance) {
+        this.acceptance = acceptance;
+    }
+
+    public final boolean isAccepted() {
+        return acceptance;
+    }
+
+    @Override
+    public final boolean authenticate(ServerSession session, String username, PublicKey clientHostKey,
+            String clientHostName, String clientUsername, List<X509Certificate> certificates) {
+        boolean accepted = isAccepted();
+        if (accepted) {
+            handleAcceptance(session, username, clientHostKey, clientHostName, clientUsername, certificates);
+        } else {
+            handleRejection(session, username, clientHostKey, clientHostName, clientUsername, certificates);
+        }
+
+        return accepted;
+    }
+
+    protected void handleAcceptance(ServerSession session, String username, PublicKey clientHostKey,
+            String clientHostName, String clientUsername, List<X509Certificate> certificates)  {
+        // accepting without really checking is dangerous, thus the warning
+        log.warn("authenticate({}[{}]: accepted without checking {}@{} key={} fingerprint={}",
+                 username, session, clientUsername, clientHostName, KeyUtils.getKeyType(clientHostKey), KeyUtils.getFingerPrint(clientHostKey));
+
+    }
+
+    protected void handleRejection(ServerSession session, String username, PublicKey clientHostKey,
+            String clientHostName, String clientUsername, List<X509Certificate> certificates)  {
+        if (log.isDebugEnabled()) {
+            log.debug("authenticate({}[{}]: rejected {}@{} key={} fingerprint={}",
+                    username, session, clientUsername, clientHostName, KeyUtils.getKeyType(clientHostKey), KeyUtils.getFingerPrint(clientHostKey));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
new file mode 100644
index 0000000..607bb36
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBased.java
@@ -0,0 +1,173 @@
+/*
+ * 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.server.auth.hostbased;
+
+import java.io.ByteArrayInputStream;
+import java.security.PublicKey;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.server.auth.AbstractUserAuth;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthHostBased extends AbstractUserAuth implements SignatureFactoriesManager {
+    public static final String NAME = UserAuthHostBasedFactory.NAME;
+
+    private List<NamedFactory<Signature>> factories;
+
+    public UserAuthHostBased() {
+        this(null);
+    }
+
+    public UserAuthHostBased(List<NamedFactory<Signature>> factories) {
+        super(NAME);
+        this.factories = factories; // OK if null/empty
+    }
+
+    @Override
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return factories;
+    }
+
+    @Override
+    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+        this.factories = factories;
+    }
+
+    @Override
+    protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
+        ValidateUtils.checkTrue(init, "Instance not initialized");
+
+        int dataLen = buffer.available();
+        String username = getUsername();
+        ServerSession session = getSession();
+        String keyType = buffer.getString();
+        int keyLen = buffer.getInt();
+        int keyOffset = buffer.rpos();
+
+        Buffer buf = new ByteArrayBuffer(buffer.array(), keyOffset, keyLen, true);
+        PublicKey clientKey = buf.getRawPublicKey();
+        List<X509Certificate> certs = Collections.<X509Certificate>emptyList();
+        if (buf.available() > 0) {
+            CertificateFactory cf = SecurityUtils.getCertificateFactory("X.509");
+            certs = new ArrayList<>();
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(buf.array(), buf.rpos(), buf.available())) {
+                X509Certificate c = (X509Certificate) cf.generateCertificate(bais);
+                certs.add(c);
+            }
+        }
+
+        buffer.rpos(keyOffset + keyLen);
+        String clientHostName = buffer.getString();
+        String clientUsername = buffer.getString();
+
+        byte[] signature = buffer.getBytes();
+        if (log.isDebugEnabled()) {
+            log.debug("doAuth({}@{}) authenticate key type={}, fingerprint={}, client={}@{}, num-certs={}",
+                      username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+                      clientUsername, clientHostName, GenericUtils.size(certs));
+        }
+
+        HostBasedAuthenticator authenticator = session.getHostBasedAuthenticator();
+        if (authenticator == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - no authenticator",
+                          username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+                          clientUsername, clientHostName, GenericUtils.size(certs));
+            }
+            return Boolean.FALSE;
+        }
+
+        boolean authed = authenticator.authenticate(session, username, clientKey, clientHostName, clientUsername, certs);
+        if (log.isDebugEnabled()) {
+            log.debug("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - authentication result: {}",
+                      username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+                      clientUsername, clientHostName, GenericUtils.size(certs), authed);
+        }
+        if (!authed) {
+            return Boolean.FALSE;
+        }
+
+        // verify signature
+        Collection<NamedFactory<Signature>> factories =
+                ValidateUtils.checkNotNullAndNotEmpty(
+                        SignatureFactoriesManager.Utils.resolveSignatureFactories(this, session),
+                        "No signature factories for session=%s",
+                        session);
+        Signature verifier = ValidateUtils.checkNotNull(
+                NamedFactory.Utils.create(factories, keyType),
+                "No verifier located for algorithm=%s",
+                keyType);
+        verifier.initVerifier(clientKey);
+
+        byte[] id = session.getSessionId();
+        buf = new ByteArrayBuffer(dataLen + id.length + Long.SIZE, false);
+        buf.putBytes(id);
+        buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+        buf.putString(username);
+        buf.putString(getService());
+        buf.putString(getName());
+        buf.putString(keyType);
+        buf.putInt(keyLen);
+        // copy the key + certificates
+        buf.putRawBytes(buffer.array(), keyOffset, keyLen);
+        buf.putString(clientHostName);
+        buf.putString(clientUsername);
+
+        if (log.isTraceEnabled()) {
+            log.trace("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - verification data: {}",
+                      username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+                      clientUsername, clientHostName, GenericUtils.size(certs), buf.printHex());
+            log.trace("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - expected signature: {}",
+                    username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+                    clientUsername, clientHostName, GenericUtils.size(certs), BufferUtils.printHex(signature));
+        }
+
+        verifier.update(buf.array(), buf.rpos(), buf.available());
+        if (!verifier.verify(signature)) {
+            throw new Exception("Key verification failed");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("doAuth({}@{}) key type={}, fingerprint={}, client={}@{}, num-certs={} - verified signature",
+                    username, session, keyType, KeyUtils.getFingerPrint(clientKey),
+                    clientUsername, clientHostName, GenericUtils.size(certs));
+        }
+        return Boolean.TRUE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBasedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBasedFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBasedFactory.java
new file mode 100644
index 0000000..9eaec57
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/UserAuthHostBasedFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.server.auth.hostbased;
+
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthHostBasedFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
+    public static final String NAME = HOST_BASED;
+    public static final UserAuthHostBasedFactory INSTANCE = new UserAuthHostBasedFactory() {
+        @Override
+        public List<NamedFactory<Signature>> getSignatureFactories() {
+            return null;
+        }
+
+        @Override
+        public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+            if (!GenericUtils.isEmpty(factories)) {
+                throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
+            }
+        }
+    };
+
+    private List<NamedFactory<Signature>> factories;
+
+    public UserAuthHostBasedFactory() {
+        this(null);
+    }
+
+    public UserAuthHostBasedFactory(List<NamedFactory<Signature>> factories) {
+        super(NAME);
+        this.factories = factories; // OK if null/empty
+    }
+
+    @Override
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return factories;
+    }
+
+    @Override
+    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+        this.factories = factories;
+    }
+
+    @Override
+    public UserAuthHostBased create() {
+        return new UserAuthHostBased(getSignatureFactories());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
new file mode 100644
index 0000000..009ddb4
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractive.java
@@ -0,0 +1,115 @@
+/*
+ * 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.server.auth.keyboard;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.server.auth.AbstractUserAuth;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * Issue a &quot;keyboard-interactive&quot; command according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthKeyboardInteractive extends AbstractUserAuth {
+    public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
+
+    public UserAuthKeyboardInteractive() {
+        super(NAME);
+    }
+
+    @Override
+    protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
+        ServerSession session = getServerSession();
+        String username = getUsername();
+        KeyboardInteractiveAuthenticator auth = session.getKeyboardInteractiveAuthenticator();
+        if (init) {
+            String lang = buffer.getString();
+            String subMethods = buffer.getString();
+            if (auth == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive authenticator to generate challenge",
+                              username, session, subMethods, lang);
+                }
+                return false;
+            }
+
+            InteractiveChallenge challenge = auth.generateChallenge(session, getUsername(), lang, subMethods);
+            if (challenge == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive challenge generated",
+                              username, session, subMethods, lang);
+                }
+                return false;
+            }
+
+            if (log.isDebugEnabled()) {
+                log.debug("doAuth({}@{})[methods={}, lang={}] challenge name={}, instruction={}, lang={}, num. prompts={}",
+                          username, session, subMethods, lang,
+                          challenge.getInteractionName(), challenge.getInteractionInstruction(),
+                          challenge.getLanguageTag(), GenericUtils.size(challenge.getPrompts()));
+            }
+
+            // Prompt for password
+            buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, BufferUtils.clear(buffer));
+            challenge.append(buffer);
+            session.writePacket(buffer);
+            return null;
+        } else {
+            int cmd = buffer.getUByte();
+            if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE) {
+                throw new SshException("Received unexpected message: " + SshConstants.getCommandMessageName(cmd));
+            }
+
+            int num = buffer.getInt();
+            List<String> responses = (num <= 0) ? Collections.<String>emptyList() : new ArrayList<String>(num);
+            for (int index = 0; index < num; index++) {
+                String value = buffer.getString();
+                if (log.isTraceEnabled()) {
+                    log.trace("doAuth({}@{}) response #{}: {}", username, session, index + 1, value);
+                }
+                responses.add(value);
+            }
+
+            if (auth == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("doAuth({}@{}) no interactive authenticator to validate {} responses",
+                              username, session, num);
+                }
+                return false;
+            }
+
+            boolean authed = auth.authenticate(session, username, responses);
+            if (log.isDebugEnabled()) {
+                log.debug("doAuth({}@{}) authenticate {} responses result: {}",
+                          username, session, num, authed);
+            }
+
+            return authed;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractiveFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
new file mode 100644
index 0000000..7166d24
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.server.auth.keyboard;
+
+import org.apache.sshd.server.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthKeyboardInteractiveFactory extends AbstractUserAuthFactory {
+    public static final String NAME = KB_INTERACTIVE;
+    public static final UserAuthKeyboardInteractiveFactory INSTANCE = new UserAuthKeyboardInteractiveFactory();
+
+    public UserAuthKeyboardInteractiveFactory() {
+        super(NAME);
+    }
+
+    @Override
+    public UserAuthKeyboardInteractive create() {
+        return new UserAuthKeyboardInteractive();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPassword.java
new file mode 100644
index 0000000..35704bc
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPassword.java
@@ -0,0 +1,141 @@
+/*
+ * 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.server.auth.password;
+
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.server.auth.AbstractUserAuth;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPassword extends AbstractUserAuth {
+    public static final String NAME = UserAuthPasswordFactory.NAME;
+
+    public UserAuthPassword() {
+        super(NAME);
+    }
+
+    @Override
+    public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
+        ValidateUtils.checkTrue(init, "Instance not initialized");
+
+        boolean newPassword = buffer.getBoolean();
+        String password = buffer.getString();
+        if (newPassword) {
+            return handleClientPasswordChangeRequest(buffer, getServerSession(), getUsername(), password, buffer.getString());
+        } else {
+            return checkPassword(buffer, getServerSession(), getUsername(), password);
+        }
+    }
+
+    /**
+     * Invokes the configured {@link PasswordAuthenticator} and returns the result.
+     * If {@link PasswordChangeRequiredException} thrown by the authenticator then
+     * {@link #handleServerPasswordChangeRequest(Buffer, ServerSession, String, String, PasswordChangeRequiredException)}
+     * is invoked
+     *
+     * @param buffer   The received {@link Buffer} to be re-used if need to send
+     *                 a password change request
+     * @param session  The {@link ServerSession} through which the request was received
+     * @param username The username
+     * @param password The password
+     * @return The authentication result - if {@code null} then exception was handled
+     * internally and authentication is still in progress
+     * @throws Exception If internal error during authentication (exception for
+     * {@link PasswordChangeRequiredException} which is handled internally)
+     * @see #handleServerPasswordChangeRequest(Buffer, ServerSession, String, String, PasswordChangeRequiredException)
+     */
+    protected Boolean checkPassword(Buffer buffer, ServerSession session, String username, String password) throws Exception {
+        PasswordAuthenticator auth = session.getPasswordAuthenticator();
+        if (auth == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("checkPassword({}) no password authenticator", session);
+            }
+            return false;
+        }
+
+        try {
+            boolean authed = auth.authenticate(username, password, session);
+            if (log.isDebugEnabled()) {
+                log.debug("checkPassword({}) authentication result: {}", session, authed);
+            }
+            return authed;
+        } catch (PasswordChangeRequiredException e) {
+            if (log.isDebugEnabled()) {
+                log.debug("checkPassword({}) password change required: {}", session, e.getMessage());
+            }
+            return handleServerPasswordChangeRequest(buffer, session, username, password, e);
+        }
+    }
+
+    /**
+     * Invoked when the client sends a {@code SSH_MSG_USERAUTH_REQUEST} indicating
+     * a password change. Throws {@link UnsupportedOperationException} by default
+     *
+     * @param buffer The {@link Buffer} to re-use in order to respond
+     * @param session The associated {@link ServerSession}
+     * @param username The username
+     * @param oldPassword The old password
+     * @param newPassword The new password
+     * @return Password change and authentication result - {@code null} means
+     * authentication incomplete - i.e., handler has sent some extra query.
+     * @throws Exception If failed to handle the request.
+     */
+    protected Boolean handleClientPasswordChangeRequest(
+            Buffer buffer, ServerSession session, String username, String oldPassword, String newPassword)
+                        throws Exception {
+        throw new UnsupportedOperationException("Password change not supported");
+    }
+
+    /**
+     * Invoked by {@link #checkPassword(Buffer, ServerSession, String, String)}
+     * when a {@link PasswordChangeRequiredException} was thrown by the authenticator.
+     * By default it re-throws the original exception.
+     *
+     * @param buffer   The received {@link Buffer} to be re-used if need to send
+     *                 a password change request
+     * @param session  The {@link ServerSession} through which the request was received
+     * @param username The username
+     * @param password The (rejected) password
+     * @param e        The original thrown exception
+     * @return {@code null} by default to indicate incomplete authentication
+     * @throws Exception If failed to dispatch the message
+     */
+    protected Boolean handleServerPasswordChangeRequest(
+            Buffer buffer, ServerSession session, String username, String password, PasswordChangeRequiredException e)
+                throws Exception {
+        String prompt = e.getPrompt();
+        String lang = e.getLanguage();
+        if (log.isDebugEnabled()) {
+            log.debug("handlePasswordChangeRequest({}) password change required - prompt={}, lang={}",
+                      session, prompt, lang);
+        }
+
+        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, buffer);
+        buffer.putString(prompt);
+        buffer.putString(lang);
+        session.writePacket(buffer);
+        return null;    // authentication incomplete
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPasswordFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPasswordFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPasswordFactory.java
new file mode 100644
index 0000000..322f552
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/password/UserAuthPasswordFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.server.auth.password;
+
+import org.apache.sshd.server.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPasswordFactory extends AbstractUserAuthFactory {
+    public static final String NAME = PASSWORD;
+    public static final UserAuthPasswordFactory INSTANCE = new UserAuthPasswordFactory();
+
+    public UserAuthPasswordFactory() {
+        super(NAME);
+    }
+
+    @Override
+    public UserAuthPassword create() {
+        return new UserAuthPassword();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
new file mode 100644
index 0000000..7540747
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKey.java
@@ -0,0 +1,166 @@
+/*
+ * 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.server.auth.pubkey;
+
+import java.security.PublicKey;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.server.auth.AbstractUserAuth;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFactoriesManager {
+    public static final String NAME = UserAuthPublicKeyFactory.NAME;
+
+    private List<NamedFactory<Signature>> factories;
+
+    public UserAuthPublicKey() {
+        this(null);
+    }
+
+    public UserAuthPublicKey(List<NamedFactory<Signature>> factories) {
+        super(NAME);
+        this.factories = factories; // OK if null/empty
+    }
+
+    @Override
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return factories;
+    }
+
+    @Override
+    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+        this.factories = factories;
+    }
+
+    @Override
+    public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
+        ValidateUtils.checkTrue(init, "Instance not initialized");
+
+        boolean hasSig = buffer.getBoolean();
+        String alg = buffer.getString();
+        int oldLim = buffer.wpos();
+        int oldPos = buffer.rpos();
+        int len = buffer.getInt();
+        buffer.wpos(buffer.rpos() + len);
+
+        ServerSession session = getServerSession();
+        String username = getUsername();
+        PublicKey key = buffer.getRawPublicKey();
+        Collection<NamedFactory<Signature>> factories =
+                ValidateUtils.checkNotNullAndNotEmpty(
+                        SignatureFactoriesManager.Utils.resolveSignatureFactories(this, session),
+                        "No signature factories for session=%s",
+                        session);
+        if (log.isDebugEnabled()) {
+            log.debug("doAuth({}@{}) verify key type={}, factories={}, fingerprint={}",
+                      username, session, alg, NamedResource.Utils.getNames(factories), KeyUtils.getFingerPrint(key));
+        }
+
+        Signature verifier = ValidateUtils.checkNotNull(
+                NamedFactory.Utils.create(factories, alg),
+                "No verifier located for algorithm=%s",
+                alg);
+        verifier.initVerifier(key);
+        buffer.wpos(oldLim);
+
+        byte[] sig = hasSig ? buffer.getBytes() : null;
+        PublickeyAuthenticator authenticator = session.getPublickeyAuthenticator();
+        if (authenticator == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("doAuth({}@{}) key type={}, fingerprint={} - no authenticator",
+                          username, session, alg, KeyUtils.getFingerPrint(key));
+            }
+            return Boolean.FALSE;
+        }
+
+        boolean authed = authenticator.authenticate(username, key, session);
+        if (log.isDebugEnabled()) {
+            log.debug("doAuth({}@{}) key type={}, fingerprint={} - authentication result: {}",
+                      username, session, alg, KeyUtils.getFingerPrint(key), authed);
+        }
+        if (!authed) {
+            return Boolean.FALSE;
+        }
+
+        if (!hasSig) {
+            if (log.isDebugEnabled()) {
+                log.debug("doAuth({}@{}) send SSH_MSG_USERAUTH_PK_OK for key type={}, fingerprint={}",
+                           username, session, alg, KeyUtils.getFingerPrint(key));
+            }
+
+            Buffer buf = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PK_OK, BufferUtils.clear(buffer));
+            buf.putString(alg);
+            buf.putRawBytes(buffer.array(), oldPos, 4 + len);
+            session.writePacket(buf);
+            return null;
+        }
+
+        // verify signature
+        byte[] id = session.getSessionId();
+        String service = getService();
+        String name = getName();
+        Buffer buf = new ByteArrayBuffer(id.length + username.length() + service.length() + name.length()
+            + alg.length() + ByteArrayBuffer.DEFAULT_SIZE + Long.SIZE, false);
+        buf.putBytes(id);
+        buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+        buf.putString(username);
+        buf.putString(service);
+        buf.putString(name);
+        buf.putBoolean(true);
+        buf.putString(alg);
+        buffer.rpos(oldPos);
+        buffer.wpos(oldPos + 4 + len);
+        buf.putBuffer(buffer);
+
+        if (log.isTraceEnabled()) {
+            log.trace("doAuth({}@{}) key type={}, fingerprint={} - verification data={}",
+                      username, session, alg, KeyUtils.getFingerPrint(key), buf.printHex());
+            log.trace("doAuth({}@{}) key type={}, fingerprint={} - expected signature={}",
+                      username, session, alg, KeyUtils.getFingerPrint(key), BufferUtils.printHex(sig));
+        }
+
+        verifier.update(buf.array(), buf.rpos(), buf.available());
+        if (!verifier.verify(sig)) {
+            throw new Exception("Key verification failed");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("doAuth({}@{}) key type={}, fingerprint={} - verified",
+                      username, session, alg, KeyUtils.getFingerPrint(key));
+        }
+
+        return Boolean.TRUE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKeyFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKeyFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKeyFactory.java
new file mode 100644
index 0000000..d53a02a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/pubkey/UserAuthPublicKeyFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.server.auth.pubkey;
+
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKeyFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
+    public static final String NAME = PUBLIC_KEY;
+    public static final UserAuthPublicKeyFactory INSTANCE = new UserAuthPublicKeyFactory() {
+        @Override
+        public List<NamedFactory<Signature>> getSignatureFactories() {
+            return null;
+        }
+
+        @Override
+        public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+            if (!GenericUtils.isEmpty(factories)) {
+                throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
+            }
+        }
+    };
+
+    private List<NamedFactory<Signature>> factories;
+
+    public UserAuthPublicKeyFactory() {
+        this(null);
+    }
+
+    public UserAuthPublicKeyFactory(List<NamedFactory<Signature>> factories) {
+        super(NAME);
+        this.factories = factories; // OK if null/empty
+    }
+
+    @Override
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return factories;
+    }
+
+    @Override
+    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+        this.factories = factories;
+    }
+
+    @Override
+    public UserAuthPublicKey create() {
+        return new UserAuthPublicKey(getSignatureFactories());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
index 2e76a7a..9abfb5b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/AbstractServerSession.java
@@ -27,6 +27,7 @@ import org.apache.sshd.common.session.AbstractSession;
 import org.apache.sshd.server.ServerFactoryManager;
 import org.apache.sshd.server.auth.UserAuth;
 import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
 import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
 import org.apache.sshd.server.auth.password.PasswordAuthenticator;
 import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
@@ -39,6 +40,7 @@ public abstract class AbstractServerSession extends AbstractSession implements S
     private PublickeyAuthenticator publickeyAuthenticator;
     private KeyboardInteractiveAuthenticator interactiveAuthenticator;
     private GSSAuthenticator gssAuthenticator;
+    private HostBasedAuthenticator hostBasedAuthenticator;
     private List<NamedFactory<UserAuth>> userAuthFactories;
 
     protected AbstractServerSession(ServerFactoryManager factoryManager, IoSession ioSession) {
@@ -91,6 +93,16 @@ public abstract class AbstractServerSession extends AbstractSession implements S
     }
 
     @Override
+    public HostBasedAuthenticator getHostBasedAuthenticator() {
+        return resolveEffectiveProvider(HostBasedAuthenticator.class, hostBasedAuthenticator, getFactoryManager().getHostBasedAuthenticator());
+    }
+
+    @Override
+    public void setHostBasedAuthenticator(HostBasedAuthenticator hostBasedAuthenticator) {
+        this.hostBasedAuthenticator = hostBasedAuthenticator;
+    }
+
+    @Override
     public List<NamedFactory<UserAuth>> getUserAuthFactories() {
         return resolveEffectiveFactories(UserAuth.class, userAuthFactories, getFactoryManager().getUserAuthFactories());
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java b/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
index de55c78..d6a4561 100644
--- a/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/SinglePublicKeyAuthTest.java
@@ -33,9 +33,9 @@ import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.server.ServerFactoryManager;
 import org.apache.sshd.server.SshServer;
-import org.apache.sshd.server.auth.UserAuthPublicKeyFactory;
 import org.apache.sshd.server.auth.pubkey.CachingPublicKeyAuthenticator;
 import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.server.auth.pubkey.UserAuthPublicKeyFactory;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.util.test.BaseTestSupport;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java b/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
index cc8e780..f06b43f 100644
--- a/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
@@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.server.ServerFactoryManager;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
index 2b6246d..b2148f2 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
@@ -24,8 +24,9 @@ import java.lang.reflect.Method;
 import java.security.KeyPair;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import org.apache.sshd.client.auth.PasswordIdentityProvider;
-import org.apache.sshd.client.auth.UserInteraction;
+
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
 import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.client.session.ClientSessionImpl;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
index b2aec0d..da4b770 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
@@ -29,7 +29,7 @@ import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
 import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.NamedFactory;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
index 4d1b9a7..b414835 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
@@ -48,11 +48,11 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.client.auth.UserAuth;
-import org.apache.sshd.client.auth.UserAuthKeyboardInteractive;
-import org.apache.sshd.client.auth.UserAuthKeyboardInteractiveFactory;
-import org.apache.sshd.client.auth.UserAuthPasswordFactory;
-import org.apache.sshd.client.auth.UserAuthPublicKeyFactory;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive;
+import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.UserAuthPasswordFactory;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
 import org.apache.sshd.client.channel.ChannelExec;
 import org.apache.sshd.client.channel.ChannelShell;
 import org.apache.sshd.client.channel.ClientChannel;
@@ -98,6 +98,8 @@ import org.apache.sshd.common.util.io.NoCloseOutputStream;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator;
+import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
+import org.apache.sshd.server.auth.password.RejectAllPasswordAuthenticator;
 import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
 import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.channel.ChannelSessionFactory;
@@ -918,21 +920,8 @@ public class ClientTest extends BaseTestSupport {
 
     @Test
     public void testPublicKeyAuth() throws Exception {
-        client.start();
-
-        try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
-            assertNotNull("Client session creation not signalled", clientSessionHolder.get());
-            KeyPair pair = createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
-            session.addPublicKeyIdentity(pair);
-            session.auth().verify(5L, TimeUnit.SECONDS);
-        } finally {
-            client.stop();
-        }
-        assertNull("Session closure not signalled", clientSessionHolder.get());
-    }
-
-    @Test
-    public void testPublicKeyAuthNew() throws Exception {
+        sshd.setPasswordAuthenticator(RejectAllPasswordAuthenticator.INSTANCE);
+        sshd.setKeyboardInteractiveAuthenticator(KeyboardInteractiveAuthenticator.NONE);
         client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPublicKeyFactory.INSTANCE));
         client.start();
 
@@ -974,7 +963,7 @@ public class ClientTest extends BaseTestSupport {
 
     @Test
     public void testPasswordAuthNew() throws Exception {
-        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthPasswordFactory()));
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPasswordFactory.INSTANCE));
         client.start();
 
         try (ClientSession session = createTestClientSession()) {
@@ -987,7 +976,7 @@ public class ClientTest extends BaseTestSupport {
 
     @Test
     public void testPasswordAuthNewWithFailureOnFirstIdentity() throws Exception {
-        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthPasswordFactory()));
+        client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(UserAuthPasswordFactory.INSTANCE));
         client.start();
 
         try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
@@ -1035,7 +1024,7 @@ public class ClientTest extends BaseTestSupport {
         final Collection<String> mismatchedPrompts = new LinkedList<String>();
         client.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(new UserAuthKeyboardInteractiveFactory() {
             @Override
-            public UserAuth create() {
+            public UserAuthKeyboardInteractive create() {
                 return new UserAuthKeyboardInteractive() {
                     @Override
                     protected boolean useCurrentPassword(String password, String name, String instruction, String lang, String[] prompt, boolean[] echo) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java b/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java
index 1a760c3..9ed8497 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/auth/PasswordIdentityProviderTest.java
@@ -26,6 +26,7 @@ import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.junit.FixMethodOrder;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java b/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
index cde7f8d..afaa8a5 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/auth/AuthenticationTest.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.net.SocketAddress;
 import java.security.KeyPair;
 import java.security.PublicKey;
+import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -34,14 +35,16 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.auth.PasswordIdentityProvider;
 import org.apache.sshd.client.auth.UserAuth;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.hostbased.HostKeyIdentityProvider;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
 import org.apache.sshd.client.future.AuthFuture;
 import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.io.IoSession;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
@@ -54,15 +57,16 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.server.ServerFactoryManager;
 import org.apache.sshd.server.SshServer;
-import org.apache.sshd.server.auth.UserAuthKeyboardInteractiveFactory;
-import org.apache.sshd.server.auth.UserAuthPasswordFactory;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
 import org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator;
 import org.apache.sshd.server.auth.keyboard.InteractiveChallenge;
 import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
 import org.apache.sshd.server.auth.keyboard.PromptEntry;
+import org.apache.sshd.server.auth.keyboard.UserAuthKeyboardInteractiveFactory;
 import org.apache.sshd.server.auth.password.PasswordAuthenticator;
 import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
 import org.apache.sshd.server.auth.password.RejectAllPasswordAuthenticator;
+import org.apache.sshd.server.auth.password.UserAuthPasswordFactory;
 import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
 import org.apache.sshd.server.auth.pubkey.RejectAllPublickeyAuthenticator;
 import org.apache.sshd.server.session.ServerSession;
@@ -164,10 +168,10 @@ public class AuthenticationTest extends BaseTestSupport {
 
         final AtomicInteger changesCount = new AtomicInteger(0);
         sshd.setUserAuthFactories(Collections.<NamedFactory<org.apache.sshd.server.auth.UserAuth>>singletonList(
-            new org.apache.sshd.server.auth.UserAuthPasswordFactory() {
+            new org.apache.sshd.server.auth.password.UserAuthPasswordFactory() {
                 @Override
-                public org.apache.sshd.server.auth.UserAuth create() {
-                    return new org.apache.sshd.server.auth.UserAuthPassword() {
+                public org.apache.sshd.server.auth.password.UserAuthPassword create() {
+                    return new org.apache.sshd.server.auth.password.UserAuthPassword() {
                         @Override
                         protected Boolean handleClientPasswordChangeRequest(
                                 Buffer buffer, ServerSession session, String username, String oldPassword, String newPassword)
@@ -214,10 +218,10 @@ public class AuthenticationTest extends BaseTestSupport {
 
             final AtomicInteger sentCount = new AtomicInteger(0);
             client.setUserAuthFactories(Collections.<NamedFactory<org.apache.sshd.client.auth.UserAuth>>singletonList(
-                new org.apache.sshd.client.auth.UserAuthPasswordFactory() {
+                new org.apache.sshd.client.auth.password.UserAuthPasswordFactory() {
                     @Override
-                    public org.apache.sshd.client.auth.UserAuth create() {
-                        return new org.apache.sshd.client.auth.UserAuthPassword() {
+                    public org.apache.sshd.client.auth.password.UserAuthPassword create() {
+                        return new org.apache.sshd.client.auth.password.UserAuthPassword() {
                             @Override
                             protected void sendPassword(Buffer buffer, ClientSession session, String oldPassword, String newPassword) throws IOException {
                                 int count = sentCount.incrementAndGet();
@@ -315,14 +319,14 @@ public class AuthenticationTest extends BaseTestSupport {
                     assertEquals("Mismatched user language",
                             PropertyResolverUtils.getStringProperty(
                                     client,
-                                    org.apache.sshd.client.auth.UserAuthKeyboardInteractive.INTERACTIVE_LANGUAGE_TAG,
-                                    org.apache.sshd.client.auth.UserAuthKeyboardInteractive.DEFAULT_INTERACTIVE_LANGUAGE_TAG),
+                                    org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive.INTERACTIVE_LANGUAGE_TAG,
+                                    org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive.DEFAULT_INTERACTIVE_LANGUAGE_TAG),
                             lang);
                     assertEquals("Mismatched client sub-methods",
                             PropertyResolverUtils.getStringProperty(
                                     client,
-                                    org.apache.sshd.client.auth.UserAuthKeyboardInteractive.INTERACTIVE_SUBMETHODS,
-                                    org.apache.sshd.client.auth.UserAuthKeyboardInteractive.DEFAULT_INTERACTIVE_SUBMETHODS),
+                                    org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive.INTERACTIVE_SUBMETHODS,
+                                    org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractive.DEFAULT_INTERACTIVE_SUBMETHODS),
                             subMethods);
 
                     InteractiveChallenge challenge = super.generateChallenge(session, username, lang, subMethods);
@@ -639,7 +643,7 @@ public class AuthenticationTest extends BaseTestSupport {
             });
 
             // allow only EC keys for public key authentication
-            org.apache.sshd.client.auth.UserAuthPublicKeyFactory factory = new org.apache.sshd.client.auth.UserAuthPublicKeyFactory();
+            org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory factory = new org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory();
             factory.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(BuiltinSignatures.nistp256, BuiltinSignatures.nistp384, BuiltinSignatures.nistp521));
             client.setUserAuthFactories(Collections.<NamedFactory<UserAuth>>singletonList(factory));
 
@@ -653,6 +657,45 @@ public class AuthenticationTest extends BaseTestSupport {
         }
     }
 
+    @Test
+    public void testHostBasedAuthentication() throws Exception {
+        final String CLIENT_USERNAME = getClass().getSimpleName();
+        final String CLIENT_HOSTNAME = SshdSocketAddress.toAddressString(SshdSocketAddress.getFirstExternalNetwork4Address());
+        final KeyPair CLIENT_HOSTKEY = Utils.generateKeyPair("RSA", 1024);
+        final AtomicInteger invocationCount = new AtomicInteger(0);
+        sshd.setHostBasedAuthenticator(new HostBasedAuthenticator() {
+            @Override
+            public boolean authenticate(ServerSession session, String username,
+                    PublicKey clientHostKey, String clientHostName, String clientUsername, List<X509Certificate> certificates) {
+                invocationCount.incrementAndGet();
+                return CLIENT_USERNAME.equals(clientUsername)
+                    && CLIENT_HOSTNAME.equals(clientHostName)
+                    && KeyUtils.compareKeys(CLIENT_HOSTKEY.getPublic(), clientHostKey);
+            }
+        });
+        sshd.setPasswordAuthenticator(RejectAllPasswordAuthenticator.INSTANCE);
+        sshd.setKeyboardInteractiveAuthenticator(KeyboardInteractiveAuthenticator.NONE);
+        sshd.setPublickeyAuthenticator(RejectAllPublickeyAuthenticator.INSTANCE);
+        sshd.setUserAuthFactories(Collections.<NamedFactory<org.apache.sshd.server.auth.UserAuth>>singletonList(org.apache.sshd.server.auth.hostbased.UserAuthHostBasedFactory.INSTANCE));
+
+        try (SshClient client = setupTestClient()) {
+            org.apache.sshd.client.auth.hostbased.UserAuthHostBasedFactory factory =
+                    new org.apache.sshd.client.auth.hostbased.UserAuthHostBasedFactory();
+            // TODO factory.setClientHostname(CLIENT_HOSTNAME);
+            factory.setClientUsername(CLIENT_USERNAME);
+            factory.setClientHostKeys(HostKeyIdentityProvider.Utils.wrap(CLIENT_HOSTKEY));
+
+            client.setUserAuthFactories(Collections.<NamedFactory<org.apache.sshd.client.auth.UserAuth>>singletonList(factory));
+            client.start();
+            try (ClientSession s = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
+                s.auth().verify(11L, TimeUnit.SECONDS);
+                assertEquals("Mismatched authenticator invocation count", 1, invocationCount.get());
+            } finally {
+                client.stop();
+            }
+        }
+    }
+
     private static void assertAuthenticationResult(String message, AuthFuture future, boolean expected) throws IOException {
         assertTrue(message + ": failed to get result on time", future.await(5L, TimeUnit.SECONDS));
         assertEquals(message + ": mismatched authentication result", expected, future.isSuccess());

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java
index fc3ddec..f4acfc0 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/ClientUserAuthServiceOld.java
@@ -20,7 +20,7 @@ package org.apache.sshd.deprecated;
 
 import java.io.IOException;
 
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
 import org.apache.sshd.client.future.AuthFuture;
 import org.apache.sshd.client.future.DefaultAuthFuture;
 import org.apache.sshd.client.session.ClientSessionImpl;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
index 6d84719..ba58e64 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthAgent.java
@@ -23,7 +23,7 @@ import java.security.PublicKey;
 import java.util.Iterator;
 
 import org.apache.sshd.agent.SshAgent;
-import org.apache.sshd.client.auth.UserAuthPublicKeyFactory;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.client.session.ClientSessionImpl;
 import org.apache.sshd.common.SshConstants;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
index 9201607..8b62602 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
@@ -21,7 +21,7 @@ package org.apache.sshd.deprecated;
 import java.io.IOException;
 import java.util.Arrays;
 
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.buffer.Buffer;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
index 43b8cfc..3c1ddca 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthPublicKey.java
@@ -21,7 +21,7 @@ package org.apache.sshd.deprecated;
 import java.io.IOException;
 import java.security.KeyPair;
 
-import org.apache.sshd.client.auth.UserAuthPublicKeyFactory;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.SshConstants;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
index f21e070..aed700d 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
@@ -41,7 +41,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.client.ClientAuthenticationManager;
 import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
 import org.apache.sshd.client.channel.ChannelExec;
 import org.apache.sshd.client.channel.ChannelShell;
 import org.apache.sshd.client.channel.ClientChannel;


[3/3] mina-sshd git commit: [SSHD-620] Add support for 'hostbased' authentication

Posted by lg...@apache.org.
[SSHD-620] Add support for 'hostbased' authentication


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

Branch: refs/heads/master
Commit: 18335089d97a76c1aec74b4c082f9a3a2bfb3517
Parents: cbff09d
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Tue Jan 5 08:05:18 2016 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Tue Jan 5 08:05:18 2016 +0200

----------------------------------------------------------------------
 .../client/ClientAuthenticationManager.java     |   4 +-
 .../java/org/apache/sshd/client/SshClient.java  |  13 +-
 .../auth/AuthenticationIdentitiesProvider.java  |   1 +
 .../client/auth/PasswordIdentityProvider.java   | 146 ---------
 .../auth/UserAuthKeyboardInteractive.java       | 304 ------------------
 .../UserAuthKeyboardInteractiveFactory.java     |  36 ---
 .../sshd/client/auth/UserAuthPassword.java      | 135 --------
 .../client/auth/UserAuthPasswordFactory.java    |  36 ---
 .../sshd/client/auth/UserAuthPublicKey.java     | 179 -----------
 .../client/auth/UserAuthPublicKeyFactory.java   |  72 -----
 .../sshd/client/auth/UserInteraction.java       | 110 -------
 .../auth/hostbased/HostKeyIdentityProvider.java |  93 ++++++
 .../auth/hostbased/UserAuthHostBased.java       | 202 ++++++++++++
 .../hostbased/UserAuthHostBasedFactory.java     |  86 ++++++
 .../keyboard/UserAuthKeyboardInteractive.java   | 306 +++++++++++++++++++
 .../UserAuthKeyboardInteractiveFactory.java     |  38 +++
 .../client/auth/keyboard/UserInteraction.java   | 110 +++++++
 .../auth/password/PasswordIdentityProvider.java | 146 +++++++++
 .../client/auth/password/UserAuthPassword.java  | 137 +++++++++
 .../auth/password/UserAuthPasswordFactory.java  |  38 +++
 .../client/auth/pubkey/UserAuthPublicKey.java   | 178 +++++++++++
 .../auth/pubkey/UserAuthPublicKeyFactory.java   |  73 +++++
 .../client/session/AbstractClientSession.java   |   4 +-
 .../client/session/ClientUserAuthService.java   |   2 +-
 .../apache/sshd/common/SshdSocketAddress.java   | 299 ++++++++++++++++++
 .../sshd/common/auth/UserAuthMethodFactory.java |   5 +
 .../apache/sshd/common/util/NumberUtils.java    |  32 +-
 .../apache/sshd/common/util/SecurityUtils.java  |  12 +
 .../server/ServerAuthenticationManager.java     |  23 +-
 .../java/org/apache/sshd/server/SshServer.java  |  12 +
 .../auth/UserAuthKeyboardInteractive.java       | 116 -------
 .../UserAuthKeyboardInteractiveFactory.java     |  36 ---
 .../sshd/server/auth/UserAuthNoneFactory.java   |   2 +-
 .../sshd/server/auth/UserAuthPassword.java      | 142 ---------
 .../server/auth/UserAuthPasswordFactory.java    |  36 ---
 .../sshd/server/auth/UserAuthPublicKey.java     | 161 ----------
 .../server/auth/UserAuthPublicKeyFactory.java   |  72 -----
 .../AcceptAllHostBasedAuthenticator.java        |  31 ++
 .../auth/hostbased/HostBasedAuthenticator.java  |  45 +++
 .../RejectAllHostBasedAuthenticator.java        |  31 ++
 .../hostbased/StaticHostBasedAuthenticator.java |  72 +++++
 .../auth/hostbased/UserAuthHostBased.java       | 173 +++++++++++
 .../hostbased/UserAuthHostBasedFactory.java     |  74 +++++
 .../keyboard/UserAuthKeyboardInteractive.java   | 115 +++++++
 .../UserAuthKeyboardInteractiveFactory.java     |  38 +++
 .../server/auth/password/UserAuthPassword.java  | 141 +++++++++
 .../auth/password/UserAuthPasswordFactory.java  |  38 +++
 .../server/auth/pubkey/UserAuthPublicKey.java   | 166 ++++++++++
 .../auth/pubkey/UserAuthPublicKeyFactory.java   |  73 +++++
 .../server/session/AbstractServerSession.java   |  12 +
 .../apache/sshd/SinglePublicKeyAuthTest.java    |   2 +-
 .../java/org/apache/sshd/WelcomeBannerTest.java |   2 +-
 .../client/ClientAuthenticationManagerTest.java |   5 +-
 .../sshd/client/ClientSessionListenerTest.java  |   2 +-
 .../java/org/apache/sshd/client/ClientTest.java |  35 +--
 .../auth/PasswordIdentityProviderTest.java      |   1 +
 .../sshd/common/auth/AuthenticationTest.java    |  73 ++++-
 .../deprecated/ClientUserAuthServiceOld.java    |   2 +-
 .../apache/sshd/deprecated/UserAuthAgent.java   |   2 +-
 .../deprecated/UserAuthKeyboardInteractive.java |   2 +-
 .../sshd/deprecated/UserAuthPublicKey.java      |   2 +-
 .../java/org/apache/sshd/server/ServerTest.java |   2 +-
 62 files changed, 2887 insertions(+), 1649 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
index ab1f154..c48701b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
@@ -23,9 +23,9 @@ import java.security.KeyPair;
 import java.util.List;
 
 import org.apache.sshd.client.auth.AuthenticationIdentitiesProvider;
-import org.apache.sshd.client.auth.PasswordIdentityProvider;
 import org.apache.sshd.client.auth.UserAuth;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
 import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.keyprovider.KeyPairProviderHolder;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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 e8da138..8375c89 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
@@ -56,12 +56,12 @@ import java.util.logging.Logger;
 
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.client.auth.AuthenticationIdentitiesProvider;
-import org.apache.sshd.client.auth.PasswordIdentityProvider;
 import org.apache.sshd.client.auth.UserAuth;
-import org.apache.sshd.client.auth.UserAuthKeyboardInteractiveFactory;
-import org.apache.sshd.client.auth.UserAuthPasswordFactory;
-import org.apache.sshd.client.auth.UserAuthPublicKeyFactory;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserAuthKeyboardInteractiveFactory;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
+import org.apache.sshd.client.auth.password.UserAuthPasswordFactory;
+import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
 import org.apache.sshd.client.channel.ChannelShell;
 import org.apache.sshd.client.channel.ClientChannel;
 import org.apache.sshd.client.config.hosts.HostConfigEntry;
@@ -1029,6 +1029,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
                     break;
                 }
 
+                i++;
                 continue;
             }
 
@@ -1109,7 +1110,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
 
                 try {
                     if (socksPort >= 0) {
-                        session.startDynamicPortForwarding(new SshdSocketAddress("localhost", socksPort));
+                        session.startDynamicPortForwarding(new SshdSocketAddress(SshdSocketAddress.LOCALHOST_NAME, socksPort));
                         Thread.sleep(Long.MAX_VALUE);
                     } else {
                         ClientChannel channel;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
index 2d0637b..56ef102 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
@@ -27,6 +27,7 @@ import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.keyprovider.KeyIdentityProvider;
 import org.apache.sshd.common.util.GenericUtils;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java
deleted file mode 100644
index 26811db..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/PasswordIdentityProvider.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.client.auth;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.Supplier;
-import org.apache.sshd.common.util.Transformer;
-import org.apache.sshd.common.util.ValidateUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface PasswordIdentityProvider {
-    PasswordIdentityProvider EMPTY_PASSWORDS_PROVIDER = new PasswordIdentityProvider() {
-        @Override
-        public Iterable<String> loadPasswords() {
-            return Collections.emptyList();
-        }
-
-        @Override
-        public String toString() {
-            return "EMPTY";
-        }
-    };
-
-    /**
-     * @return The currently available passwords - never {@code null}
-     */
-    Iterable<String> loadPasswords();
-
-    /**
-     * A helper class for password identity provider related operations
-     * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
-     */
-    // CHECKSTYLE:OFF
-    final class Utils {
-    // CHECKSTYLE:ON
-        public static final Transformer<PasswordIdentityProvider, Iterable<String>> LOADER =
-            new Transformer<PasswordIdentityProvider, Iterable<String>>() {
-                @Override
-                public Iterable<String> transform(PasswordIdentityProvider p) {
-                    return (p == null) ? null : p.loadPasswords();
-                }
-            };
-
-        private Utils() {
-            throw new UnsupportedOperationException("No instance allowed");
-        }
-
-        public static Iterator<String> iteratorOf(ClientSession session) {
-            ValidateUtils.checkNotNull(session, "No session");
-            return iteratorOf(session.getRegisteredIdentities(), session.getPasswordIdentityProvider());
-        }
-
-        public static Iterator<String> iteratorOf(PasswordIdentityProvider identities, PasswordIdentityProvider passwords) {
-            return iteratorOf(resolvePasswordIdentityProvider(identities, passwords));
-        }
-
-        /**
-         * Resolves a non-{@code null} iterator of the available passwords
-         *
-         * @param provider The {@link PasswordIdentityProvider} - ignored if {@code null}
-         * @return A non-{@code null} iterator - which may be empty if no provider or no passwords
-         */
-        public static Iterator<String> iteratorOf(PasswordIdentityProvider provider) {
-            return GenericUtils.iteratorOf((provider == null) ? null : provider.loadPasswords());
-        }
-
-        public static PasswordIdentityProvider resolvePasswordIdentityProvider(PasswordIdentityProvider identities, PasswordIdentityProvider passwords) {
-            if ((passwords == null) || (identities == passwords)) {
-                return identities;
-            } else if (identities == null) {
-                return passwords;
-            } else {
-                return multiProvider(identities, passwords);
-            }
-        }
-
-        public static PasswordIdentityProvider multiProvider(PasswordIdentityProvider ... providers) {
-            return multiProvider(GenericUtils.isEmpty(providers) ? Collections.<PasswordIdentityProvider>emptyList() : Arrays.asList(providers));
-        }
-
-        public static PasswordIdentityProvider multiProvider(Collection<? extends PasswordIdentityProvider> providers) {
-            return wrap(iterableOf(providers));
-        }
-
-        public static Iterable<String> iterableOf(Collection<? extends PasswordIdentityProvider> providers) {
-            if (GenericUtils.isEmpty(providers)) {
-                return Collections.emptyList();
-            }
-
-            Collection<Supplier<Iterable<String>>> suppliers = new ArrayList<Supplier<Iterable<String>>>(providers.size());
-            for (final PasswordIdentityProvider p : providers) {
-                if (p == null) {
-                    continue;
-                }
-
-                suppliers.add(new Supplier<Iterable<String>>() {
-                    @Override
-                    public Iterable<String> get() {
-                        return p.loadPasswords();
-                    }
-                });
-            }
-
-            if (GenericUtils.isEmpty(suppliers)) {
-                return Collections.emptyList();
-            }
-
-            return GenericUtils.multiIterableSuppliers(suppliers);
-        }
-
-        public static PasswordIdentityProvider wrap(final Iterable<String> passwords) {
-            return new PasswordIdentityProvider() {
-                @Override
-                public Iterable<String> loadPasswords() {
-                    return passwords;
-                }
-            };
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
deleted file mode 100644
index 9327236..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.sshd.client.ClientAuthenticationManager;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.PropertyResolverUtils;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-
-/**
- * Manages a &quot;keyboard-interactive&quot; exchange according to
- * <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthKeyboardInteractive extends AbstractUserAuth {
-    public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
-
-    public static final String INTERACTIVE_LANGUAGE_TAG = "kb-client-interactive-language-tag";
-
-    /*
-     * As per RFC-4256:
-     *
-     *      The language tag is deprecated and SHOULD be the empty string.  It
-     *      may be removed in a future revision of this specification.  Instead,
-     *      the server SHOULD select the language to be used based on the tags
-     *      communicated during key exchange
-     */
-    public static final String DEFAULT_INTERACTIVE_LANGUAGE_TAG = "";
-
-    public static final String INTERACTIVE_SUBMETHODS = "kb-client-interactive-sub-methods";
-
-    /*
-     * As per RFC-4256:
-     *
-     *      The submethods field is included so the user can give a hint of which
-     *      actual methods he wants to use.  It is a comma-separated list of
-     *      authentication submethods (software or hardware) that the user
-     *      prefers.  If the client has knowledge of the submethods preferred by
-     *      the user, presumably through a configuration setting, it MAY use the
-     *      submethods field to pass this information to the server.  Otherwise,
-     *      it MUST send the empty string.
-     *
-     *      The actual names of the submethods is something the user and the
-     *      server need to agree upon.
-     *
-     *      Server interpretation of the submethods field is implementation-
-     *      dependent.
-     */
-    public static final String DEFAULT_INTERACTIVE_SUBMETHODS = "";
-
-    private final AtomicBoolean requestPending = new AtomicBoolean(false);
-    private final AtomicInteger trialsCount = new AtomicInteger(0);
-    private Iterator<String> passwords;
-    private int maxTrials;
-
-    public UserAuthKeyboardInteractive() {
-        super(NAME);
-    }
-
-    @Override
-    public void init(ClientSession session, String service) throws Exception {
-        super.init(session, service);
-        passwords = PasswordIdentityProvider.Utils.iteratorOf(session);
-        maxTrials = PropertyResolverUtils.getIntProperty(session, ClientAuthenticationManager.PASSWORD_PROMPTS, ClientAuthenticationManager.DEFAULT_PASSWORD_PROMPTS);
-        ValidateUtils.checkTrue(maxTrials > 0, "Non-positive max. trials: %d", maxTrials);
-    }
-
-    @Override
-    protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
-        String name = getName();
-        if (requestPending.get()) {
-            if (log.isDebugEnabled()) {
-                log.debug("sendAuthDataRequest({})[{}] no reply for previous request for {}",
-                          session, service, name);
-            }
-            return false;
-        }
-
-        if (!verifyTrialsCount(session, service, SshConstants.SSH_MSG_USERAUTH_REQUEST, trialsCount.get(), maxTrials)) {
-            return false;
-        }
-
-        String username = session.getUsername();
-        String lang = getExchangeLanguageTag(session);
-        String subMethods = getExchangeSubMethods(session);
-        if (log.isDebugEnabled()) {
-            log.debug("sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST for {}: lang={}, methods={}",
-                      session, service, name, lang, subMethods);
-        }
-
-        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
-                            username.length() + service.length() + name.length()
-                          + GenericUtils.length(lang) + GenericUtils.length(subMethods)
-                          + Long.SIZE /* a bit extra for the lengths */);
-        buffer.putString(username);
-        buffer.putString(service);
-        buffer.putString(name);
-        buffer.putString(lang);
-        buffer.putString(subMethods);
-        requestPending.set(true);
-        session.writePacket(buffer);
-        return true;
-    }
-
-    @Override
-    protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
-        int cmd = buffer.getUByte();
-        if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST) {
-            throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
-                            + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
-        }
-
-        requestPending.set(false);
-
-        if (!verifyTrialsCount(session, service, cmd, trialsCount.incrementAndGet(), maxTrials)) {
-            return false;
-        }
-
-        String name = buffer.getString();
-        String instruction = buffer.getString();
-        String lang = buffer.getString();
-        int num = buffer.getInt();
-        if (log.isDebugEnabled()) {
-            log.debug("processAuthDataRequest({})[{}] SSH_MSG_USERAUTH_INFO_REQUEST name={}, instruction={}, language={}, num-prompts={}",
-                      session, service, name, instruction, lang, num);
-        }
-
-        String[] prompt = new String[num];
-        boolean[] echo = new boolean[num];
-        for (int i = 0; i < num; i++) {
-            // according to RFC4256: "The prompt field(s) MUST NOT be empty strings."
-            prompt[i] = buffer.getString();
-            echo[i] = buffer.getBoolean();
-        }
-
-        if (log.isTraceEnabled()) {
-            log.trace("processAuthDataRequest({})[{}] Prompt: {}", session, service, Arrays.toString(prompt));
-            log.trace("processAuthDataRequest({})[{}] Echo: {}", session, service, Arrays.toString(echo));
-        }
-
-        String[] rep = getUserResponses(name, instruction, lang, prompt, echo);
-        if (rep == null) {
-            if (log.isDebugEnabled()) {
-                log.debug("processAuthDataRequest({})[{}] no responses for {}", session, service, name);
-            }
-            return false;
-        }
-
-        /*
-         * According to RFC4256:
-         *
-         *      If the num-responses field does not match the num-prompts
-         *      field in the request message, the server MUST send a failure
-         *      message.
-         *
-         * However it is the server's (!) responsibility to fail, so we only warn...
-         */
-        if (num != rep.length) {
-            log.warn("processAuthDataRequest({})[{}] Mismatched prompts ({}) vs. responses count ({})",
-                     session, service, num, rep.length);
-        }
-
-        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE, BufferUtils.clear(buffer));
-        buffer.putInt(rep.length);
-        for (int index = 0; index < rep.length; index++) {
-            String r = rep[index];
-            if (log.isTraceEnabled()) {
-                log.trace("processAuthDataRequest({})[{}] response #{}: {}", session, service, index + 1, r);
-            }
-            buffer.putString(r);
-        }
-
-        session.writePacket(buffer);
-        return true;
-    }
-
-    protected String getExchangeLanguageTag(ClientSession session) {
-        return PropertyResolverUtils.getStringProperty(session, INTERACTIVE_LANGUAGE_TAG, DEFAULT_INTERACTIVE_LANGUAGE_TAG);
-    }
-
-    protected String getExchangeSubMethods(ClientSession session) {
-        return PropertyResolverUtils.getStringProperty(session, INTERACTIVE_SUBMETHODS, DEFAULT_INTERACTIVE_SUBMETHODS);
-    }
-
-    protected String getCurrentPasswordCandidate() {
-        if ((passwords != null) && passwords.hasNext()) {
-            return passwords.next();
-        } else {
-            return null;
-        }
-    }
-
-    protected boolean verifyTrialsCount(ClientSession session, String service, int cmd, int nbTrials, int maxAllowed) {
-        if (log.isDebugEnabled()) {
-            log.debug("verifyTrialsCount({})[{}] cmd={} - {} out of {}",
-                      session, service, getAuthCommandName(cmd), nbTrials, maxAllowed);
-        }
-
-        return nbTrials <= maxAllowed;
-    }
-
-    /**
-     * @param name        The interaction name - may be empty
-     * @param instruction The instruction - may be empty
-     * @param lang        The language tag - may be empty
-     * @param prompt      The prompts - may be empty
-     * @param echo        Whether to echo the response for the prompt or not - same
-     *                    length as the prompts
-     * @return The response for each prompt - if {@code null} then the assumption
-     * is that some internal error occurred and no response is sent. <B>Note:</B>
-     * according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
-     * the number of responses should be <U>exactly</U> the same as the number
-     * of prompts. However, since it is the <U>server's</U> responsibility to
-     * enforce this we do not validate the response (other than logging it as
-     * a warning...)
-     */
-    protected String[] getUserResponses(String name, String instruction, String lang, String[] prompt, boolean[] echo) {
-        ClientSession session = getClientSession();
-        int num = GenericUtils.length(prompt);
-        if (num == 0) {
-            if (log.isDebugEnabled()) {
-                log.debug("getUserResponses({}) no prompts for interaction={}", session, name);
-            }
-            return GenericUtils.EMPTY_STRING_ARRAY;
-        }
-
-        String candidate = getCurrentPasswordCandidate();
-        if (useCurrentPassword(candidate, name, instruction, lang, prompt, echo)) {
-            if (log.isDebugEnabled()) {
-                log.debug("getUserResponses({}) use password candidate for interaction={}", session, name);
-            }
-            return new String[]{candidate};
-        }
-
-        UserInteraction ui = session.getUserInteraction();
-        if ((ui != null) && ui.isInteractionAllowed(session)) {
-            return ui.interactive(session, name, instruction, lang, prompt, echo);
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("getUserResponses({}) no user interaction for name={}", session, name);
-        }
-
-        return null;
-    }
-
-    protected boolean useCurrentPassword(String password, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
-        int num = GenericUtils.length(prompt);
-        if ((num != 1) || (password == null) || echo[0]) {
-            return false;
-        }
-
-        // check that prompt is something like "XXX password YYY:"
-        String value = GenericUtils.trimToEmpty(prompt[0]).toLowerCase();
-        int passPos = value.lastIndexOf("password");
-        if (passPos < 0) {  // no password keyword in prompt
-            return false;
-        }
-
-        int sepPos = value.lastIndexOf(':');
-        if (sepPos <= passPos) {    // no prompt separator or separator before the password keyword
-            return false;
-        }
-
-        return true;
-    }
-
-    public static String getAuthCommandName(int cmd) {
-        switch(cmd) {
-            case SshConstants.SSH_MSG_USERAUTH_REQUEST:
-                return "SSH_MSG_USERAUTH_REQUEST";
-            case SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST:
-                return "SSH_MSG_USERAUTH_INFO_REQUEST";
-            default:
-                return SshConstants.getCommandMessageName(cmd);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractiveFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractiveFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractiveFactory.java
deleted file mode 100644
index 5cf1068..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractiveFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthKeyboardInteractiveFactory extends AbstractUserAuthFactory {
-    public static final String NAME = KB_INTERACTIVE;
-    public static final UserAuthKeyboardInteractiveFactory INSTANCE = new UserAuthKeyboardInteractiveFactory();
-
-    public UserAuthKeyboardInteractiveFactory() {
-        super(NAME);
-    }
-
-    @Override
-    public UserAuth create() {
-        return new UserAuthKeyboardInteractive();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
deleted file mode 100644
index d4ed6f7..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Objects;
-
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-
-/**
- * Implements the &quot;password&quot; authentication mechanism
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPassword extends AbstractUserAuth {
-    public static final String NAME = UserAuthPasswordFactory.NAME;
-
-    private Iterator<String> passwords;
-    private String current;
-
-    public UserAuthPassword() {
-        super(NAME);
-    }
-
-    @Override
-    public void init(ClientSession session, String service) throws Exception {
-        super.init(session, service);
-        passwords = PasswordIdentityProvider.Utils.iteratorOf(session);
-    }
-
-    @Override
-    protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
-        if ((passwords == null) || (!passwords.hasNext())) {
-            if (log.isDebugEnabled()) {
-                log.debug("sendAuthDataRequest({})[{}] no more passwords to send", session, service);
-            }
-
-            return false;
-        }
-
-        current = passwords.next();
-        String username = session.getUsername();
-        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
-                            username.length() + service.length() + getName().length() + current.length() + Integer.SIZE);
-        sendPassword(buffer, session, current, current);
-        return true;
-    }
-
-    @Override
-    protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
-        int cmd = buffer.getUByte();
-        if (cmd != SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
-            throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
-                            + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
-        }
-
-        String prompt = buffer.getString();
-        String lang = buffer.getString();
-        UserInteraction ui = session.getUserInteraction();
-        if ((ui != null) && ui.isInteractionAllowed(session)) {
-            String password = ui.getUpdatedPassword(session, prompt, lang);
-            if (GenericUtils.isEmpty(password)) {
-                if (log.isDebugEnabled()) {
-                    log.debug("processAuthDataRequest({})[{}] No updated password for prompt={}, lang={}",
-                              session, service, prompt, lang);
-                }
-            } else {
-                sendPassword(buffer, session, password, password);
-                return true;
-            }
-        } else {
-            if (log.isDebugEnabled()) {
-                log.debug("processAuthDataRequest({})[{}] no UI for password change request for prompt={}, lang={}",
-                          session, service, prompt, lang);
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Sends the password via a {@code SSH_MSG_USERAUTH_REQUEST} message.
-     * If old and new password are not the same then it requests a password
-     * modification from the server (which may be denied if the server does
-     * not support this feature).
-     *
-     * @param buffer The {@link Buffer} to re-use for sending the message
-     * @param session The target {@link ClientSession}
-     * @param oldPassword The previous password
-     * @param newPassword The new password
-     * @throws IOException If failed to send the message.
-     */
-    protected void sendPassword(Buffer buffer, ClientSession session, String oldPassword, String newPassword) throws IOException {
-        String username = session.getUsername();
-        String service = getService();
-        String name = getName();
-        boolean modified = !Objects.equals(oldPassword, newPassword);
-        if (log.isDebugEnabled()) {
-            log.debug("sendPassword({})[{}] send SSH_MSG_USERAUTH_REQUEST for {} - modified={}",
-                      session, service, name, modified);
-        }
-
-        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, BufferUtils.clear(buffer));
-        buffer.putString(username);
-        buffer.putString(service);
-        buffer.putString(name);
-        buffer.putBoolean(modified);
-        // see RFC-4252 section 8
-        buffer.putString(oldPassword);
-        if (modified) {
-            buffer.putString(newPassword);
-        }
-        session.writePacket(buffer);
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPasswordFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPasswordFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPasswordFactory.java
deleted file mode 100644
index 14ecfb0..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPasswordFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPasswordFactory extends AbstractUserAuthFactory {
-    public static final String NAME = PASSWORD;
-    public static final UserAuthPasswordFactory INSTANCE = new UserAuthPasswordFactory();
-
-    public UserAuthPasswordFactory() {
-        super(NAME);
-    }
-
-    @Override
-    public UserAuth create() {
-        return new UserAuthPassword();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
deleted file mode 100644
index f800cad..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.security.PublicKey;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.sshd.client.auth.pubkey.PublicKeyIdentity;
-import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyIterator;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.kex.KeyExchange;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesManager;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-
-/**
- * Implements the &quot;publickey&quot; authentication mechanism
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFactoriesManager {
-    public static final String NAME = UserAuthPublicKeyFactory.NAME;
-
-    private Iterator<PublicKeyIdentity> keys;
-    private PublicKeyIdentity current;
-    private List<NamedFactory<Signature>> factories;
-
-    public UserAuthPublicKey() {
-        this(null);
-    }
-
-    public UserAuthPublicKey(List<NamedFactory<Signature>> factories) {
-        super(NAME);
-        this.factories = factories; // OK if null/empty
-    }
-
-    @Override
-    public List<NamedFactory<Signature>> getSignatureFactories() {
-        return factories;
-    }
-
-    @Override
-    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
-        this.factories = factories;
-    }
-
-    @Override
-    public void init(ClientSession session, String service) throws Exception {
-        super.init(session, service);
-        releaseKeys();  // just making sure in case multiple calls to the method
-        keys = new UserAuthPublicKeyIterator(session, this);
-    }
-
-    @Override
-    protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
-        if ((keys == null) || (!keys.hasNext())) {
-            if (log.isDebugEnabled()) {
-                log.debug("sendAuthDataRequest({})[{}] no more keys to send", session, service);
-            }
-
-            return false;
-        }
-
-        current = keys.next();
-        if (log.isTraceEnabled()) {
-            log.trace("sendAuthDataRequest({})[{}] current key details: {}", session, service, current);
-        }
-
-        PublicKey key = current.getPublicKey();
-        String algo = KeyUtils.getKeyType(key);
-        String name = getName();
-        if (log.isDebugEnabled()) {
-            log.debug("sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST request {} type={} - fingerprint={}",
-                      session, service, name, algo, KeyUtils.getFingerPrint(key));
-        }
-        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
-        buffer.putString(session.getUsername());
-        buffer.putString(service);
-        buffer.putString(name);
-        buffer.putBoolean(false);
-        buffer.putString(algo);
-        buffer.putPublicKey(key);
-        session.writePacket(buffer);
-        return true;
-    }
-
-    @Override
-    protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
-        int cmd = buffer.getUByte();
-        if (cmd != SshConstants.SSH_MSG_USERAUTH_PK_OK) {
-            throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
-                    + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
-        }
-
-        PublicKey key = current.getPublicKey();
-        String algo = KeyUtils.getKeyType(key);
-        String name = getName();
-        if (log.isDebugEnabled()) {
-            log.debug("processAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_PK_OK reply {} type={} - fingerprint={}",
-                      session, service, name, algo, KeyUtils.getFingerPrint(key));
-        }
-
-        String username = session.getUsername();
-        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, BufferUtils.clear(buffer));
-        buffer.putString(username);
-        buffer.putString(service);
-        buffer.putString(name);
-        buffer.putBoolean(true);
-        buffer.putString(algo);
-        buffer.putPublicKey(key);
-
-        Buffer bs = new ByteArrayBuffer();
-        KeyExchange kex = session.getKex();
-        bs.putBytes(kex.getH());
-        bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
-        bs.putString(username);
-        bs.putString(service);
-        bs.putString(name);
-        bs.putBoolean(true);
-        bs.putString(algo);
-        bs.putPublicKey(key);
-
-        byte[] sig = current.sign(bs.getCompactData());
-        bs = new ByteArrayBuffer(algo.length() + sig.length + Long.SIZE, false);
-        bs.putString(algo);
-        bs.putBytes(sig);
-        buffer.putBytes(bs.array(), bs.rpos(), bs.available());
-
-        session.writePacket(buffer);
-        return true;
-    }
-
-    @Override
-    public void destroy() {
-        try {
-            releaseKeys();
-        } catch (IOException e) {
-            throw new RuntimeException("Failed (" + e.getClass().getSimpleName() + ") to close agent: " + e.getMessage(), e);
-        }
-
-        super.destroy(); // for logging
-    }
-
-    protected void releaseKeys() throws IOException {
-        try {
-            if (keys instanceof Closeable) {
-                if (log.isTraceEnabled()) {
-                    log.trace("releaseKeys({}) closing {}", getClientSession(), keys);
-                }
-                ((Closeable) keys).close();
-            }
-        } finally {
-            keys = null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKeyFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKeyFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKeyFactory.java
deleted file mode 100644
index f7ccd54..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKeyFactory.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-import java.util.List;
-
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesManager;
-import org.apache.sshd.common.util.GenericUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPublicKeyFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
-    public static final String NAME = PUBLIC_KEY;
-    public static final UserAuthPublicKeyFactory INSTANCE = new UserAuthPublicKeyFactory() {
-        @Override
-        public List<NamedFactory<Signature>> getSignatureFactories() {
-            return null;
-        }
-
-        @Override
-        public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
-            if (!GenericUtils.isEmpty(factories)) {
-                throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
-            }
-        }
-    };
-
-    private List<NamedFactory<Signature>> factories;
-
-    public UserAuthPublicKeyFactory() {
-        this(null);
-    }
-
-    public UserAuthPublicKeyFactory(List<NamedFactory<Signature>> factories) {
-        super(NAME);
-        this.factories = factories; // OK if null/empty
-    }
-
-    @Override
-    public List<NamedFactory<Signature>> getSignatureFactories() {
-        return factories;
-    }
-
-    @Override
-    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
-        this.factories = factories;
-    }
-
-    @Override
-    public UserAuth create() {
-        return new UserAuthPublicKey(getSignatureFactories());
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/UserInteraction.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserInteraction.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserInteraction.java
deleted file mode 100644
index 700055a..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserInteraction.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-import org.apache.sshd.client.session.ClientSession;
-
-/**
- * Interface used by the ssh client to communicate with the end user.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- * @see <a href="https://www.ietf.org/rfc/rfc4256.txt">RFC 4256</A>
- */
-public interface UserInteraction {
-    /**
-     * A useful &quot;placeholder&quot; that indicates that no interaction is expected.
-     * <B>Note:</B> throws {@link IllegalStateException} is any of the interaction
-     * methods is called
-     */
-    UserInteraction NONE = new UserInteraction() {
-        @Override
-        public boolean isInteractionAllowed(ClientSession session) {
-            return false;
-        }
-
-        @Override
-        public void welcome(ClientSession session, String banner, String lang) {
-            // ignored
-        }
-
-        @Override
-        public String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
-            throw new IllegalStateException("interactive(" + session + ")[" + name + "] unexpected call");
-        }
-
-        @Override
-        public String getUpdatedPassword(ClientSession session, String prompt, String lang) {
-            throw new IllegalStateException("getUpdatedPassword(" + session + ")[" + prompt + "] unexpected call");
-        }
-
-        @Override
-        public String toString() {
-            return "NONE";
-        }
-    };
-
-    /**
-     *
-     * @param session The {@link ClientSession}
-     * @return {@code true} if user interaction allowed for this session
-     */
-    boolean isInteractionAllowed(ClientSession session);
-
-    /**
-     * Displays the welcome banner to the user.
-     *
-     * @param session The {@link ClientSession} through which the banner was received
-     * @param banner  The welcome banner
-     * @param lang    The banner language code - may be empty
-     */
-    void welcome(ClientSession session, String banner, String lang);
-
-    /**
-     * Invoked when &quot;keyboard-interactive&quot; authentication mechanism
-     * is used in order to provide responses for the server's challenges
-     * (a.k.a. prompts)
-     *
-     * @param session     The {@link ClientSession} through which the request was received
-     * @param name        The interaction name (may be empty)
-     * @param instruction The instruction (may be empty)
-     * @param lang        The language for the data (may be empty)
-     * @param prompt      The prompts to be displayed (may be empty)
-     * @param echo        For each prompt whether to echo the user's response
-     * @return The replies - <B>Note:</B> the protocol states that the number
-     * of replies should be <U>exactly</U> the same as the number of prompts,
-     * however we do not enforce it since it is defined as the <U>server's</U>
-     * job to check and manage this violation.
-     */
-    String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo);
-
-    /**
-     * Invoked when the server returns an {@code SSH_MSG_USERAUTH_PASSWD_CHANGEREQ}
-     * response indicating that the password should be changed - e.g., expired or
-     * not strong enough (as per the server's policy).
-     *
-     * @param session The {@link ClientSession} through which the request was received
-     * @param prompt The server's prompt (may be empty)
-     * @param lang The prompt's language (may be empty)
-     * @return The password to use - if {@code null}/empty then no updated
-     * password was provided - thus failing the authentication via passwords
-     * (<B>Note:</B> authentication might still succeed via some other means -
-     * be it other passwords, public keys, etc...)
-     */
-    String getUpdatedPassword(ClientSession session, String prompt, String lang);
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/HostKeyIdentityProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/HostKeyIdentityProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/HostKeyIdentityProvider.java
new file mode 100644
index 0000000..7819422
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/HostKeyIdentityProvider.java
@@ -0,0 +1,93 @@
+/*
+ * 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.auth.hostbased;
+
+import java.security.KeyPair;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Pair;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface HostKeyIdentityProvider {
+    /**
+     * @return The host keys as a {@link Pair} of key + certificates (which can be {@code null}/empty)
+     */
+    Iterable<Pair<KeyPair, List<X509Certificate>>> loadHostKeys();
+
+    /**
+     * A helper class for key identity provider related operations
+     * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+     */
+    // CHECKSTYLE:OFF
+    final class Utils {
+    // CHECKSTYLE:ON
+        private Utils() {
+            throw new UnsupportedOperationException("No instance allowed");
+        }
+
+        public static Iterator<Pair<KeyPair, List<X509Certificate>>> iteratorOf(HostKeyIdentityProvider provider) {
+            return GenericUtils.iteratorOf((provider == null) ? null : provider.loadHostKeys());
+        }
+
+        public static HostKeyIdentityProvider wrap(KeyPair ... pairs) {
+            return wrap(GenericUtils.isEmpty(pairs) ? Collections.<KeyPair>emptyList() : Arrays.asList(pairs));
+        }
+
+        public static HostKeyIdentityProvider wrap(final Iterable<? extends KeyPair> pairs) {
+            return new HostKeyIdentityProvider() {
+                @Override
+                public Iterable<Pair<KeyPair, List<X509Certificate>>> loadHostKeys() {
+                    return new Iterable<Pair<KeyPair, List<X509Certificate>>>() {
+                        @Override
+                        public Iterator<Pair<KeyPair, List<X509Certificate>>> iterator() {
+                            final Iterator<? extends KeyPair> iter = GenericUtils.iteratorOf(pairs);
+                            return new Iterator<Pair<KeyPair, List<X509Certificate>>>() {
+
+                                @Override
+                                public boolean hasNext() {
+                                    return iter.hasNext();
+                                }
+
+                                @Override
+                                public Pair<KeyPair, List<X509Certificate>> next() {
+                                    KeyPair kp = iter.next();
+                                    return new Pair<KeyPair, List<X509Certificate>>(kp, Collections.<X509Certificate>emptyList());
+                                }
+
+                                @Override
+                                public void remove() {
+                                    throw new UnsupportedOperationException("No removal allowed");
+                                }
+                            };
+                        }
+                    };
+                }
+
+            };
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBased.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBased.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBased.java
new file mode 100644
index 0000000..a8313f3
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBased.java
@@ -0,0 +1,202 @@
+/*
+ * 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.auth.hostbased;
+
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuth;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.Pair;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthHostBased extends AbstractUserAuth implements SignatureFactoriesManager {
+    public static final String NAME = UserAuthHostBasedFactory.NAME;
+
+    private Iterator<Pair<KeyPair, List<X509Certificate>>> keys;
+    private final HostKeyIdentityProvider clientHostKeys;
+    private List<NamedFactory<Signature>> factories;
+    private String clientUsername;
+    private String clientHostname;
+
+    public UserAuthHostBased(HostKeyIdentityProvider clientHostKeys) {
+        super(NAME);
+        this.clientHostKeys = clientHostKeys;   // OK if null
+    }
+
+    @Override
+    public void init(ClientSession session, String service) throws Exception {
+        super.init(session, service);
+        keys = HostKeyIdentityProvider.Utils.iteratorOf(clientHostKeys);  // in case multiple calls to the method
+    }
+
+    @Override
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return factories;
+    }
+
+    @Override
+    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+        this.factories = factories;
+    }
+
+    public String getClientUsername() {
+        return clientUsername;
+    }
+
+    public void setClientUsername(String clientUsername) {
+        this.clientUsername = clientUsername;
+    }
+
+    public String getClientHostname() {
+        return clientHostname;
+    }
+
+    public void setClientHostname(String clientHostname) {
+        this.clientHostname = clientHostname;
+    }
+
+    @Override
+    protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
+        if ((keys == null) || (!keys.hasNext())) {
+            if (log.isDebugEnabled()) {
+                log.debug("sendAuthDataRequest({})[{}] no more keys to send", session, service);
+            }
+
+            return false;
+        }
+
+        Pair<KeyPair, List<X509Certificate>> keyInfo = keys.next();
+        KeyPair kp = keyInfo.getFirst();
+        PublicKey pub = kp.getPublic();
+        String keyType = KeyUtils.getKeyType(pub);
+        if (log.isTraceEnabled()) {
+            log.trace("sendAuthDataRequest({})[{}] current key details: type={}, fingerprint={}",
+                      session, service, keyType, KeyUtils.getFingerPrint(pub));
+        }
+
+        Collection<NamedFactory<Signature>> factories =
+                ValidateUtils.checkNotNullAndNotEmpty(
+                        SignatureFactoriesManager.Utils.resolveSignatureFactories(this, session),
+                        "No signature factories for session=%s",
+                        session);
+        Signature verifier = ValidateUtils.checkNotNull(
+                NamedFactory.Utils.create(factories, keyType),
+                "No signer could be located for key type=%s",
+                keyType);
+
+        byte[] id = session.getSessionId();
+        String username = session.getUsername();
+        String clientUsername = resolveClientUsername();
+        String clientHostname = resolveClientHostname();
+        if (log.isDebugEnabled()) {
+            log.debug("sendAuthDataRequest({})[{}] client={}@{}",
+                      session, service, clientUsername, clientHostname);
+        }
+
+        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
+                id.length + username.length() + service.length() + clientUsername.length() + clientHostname.length()
+              + keyType.length() + ByteArrayBuffer.DEFAULT_SIZE + Long.SIZE);
+        buffer.clear();
+
+        buffer.putRawPublicKey(pub);
+
+        List<X509Certificate> certs = keyInfo.getSecond();
+        if (GenericUtils.size(certs) > 0) {
+            for (X509Certificate c : certs) {
+                // TODO make sure this yields DER encoding
+                buffer.putRawBytes(c.getEncoded());
+            }
+        }
+        byte[] keyBytes = buffer.getCompactData();
+
+        buffer.clear();
+        buffer.putBytes(id);
+        buffer.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+        buffer.putString(username);
+        buffer.putString(getService());
+        buffer.putString(getName());
+        buffer.putString(keyType);
+        buffer.putBytes(keyBytes);
+        buffer.putString(clientHostname);
+        buffer.putString(clientUsername);
+
+        verifier.initSigner(kp.getPrivate());
+        verifier.update(buffer.array(), buffer.rpos(), buffer.available());
+        byte[] signature = verifier.sign();
+        if (log.isTraceEnabled()) {
+            log.trace("sendAuthDataRequest({})[{}] type={}, fingerprint={}, client={}@{}: signature={}",
+                      session, service, keyType, KeyUtils.getFingerPrint(pub),
+                      clientUsername, clientHostname, BufferUtils.printHex(signature));
+        }
+
+        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, buffer);
+        buffer.putString(username);
+        buffer.putString(getService());
+        buffer.putString(getName());
+        buffer.putString(keyType);
+        buffer.putBytes(keyBytes);
+        buffer.putString(clientHostname);
+        buffer.putString(clientUsername);
+        buffer.putBytes(signature);
+
+        session.writePacket(buffer);
+        return true;
+    }
+
+    @Override
+    protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
+        int cmd = buffer.getUByte();
+        throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
+                    + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
+    }
+
+    protected String resolveClientUsername() {
+        String value = getClientUsername();
+        return GenericUtils.isEmpty(value) ? OsUtils.getCurrentUser() : value;
+    }
+
+    protected String resolveClientHostname() {
+        String value = getClientHostname();
+        if (GenericUtils.isEmpty(value)) {
+            value = SshdSocketAddress.toAddressString(SshdSocketAddress.getFirstExternalNetwork4Address());
+        }
+
+        return GenericUtils.isEmpty(value) ? SshdSocketAddress.LOCALHOST_IP : value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBasedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBasedFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBasedFactory.java
new file mode 100644
index 0000000..8ead888
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/hostbased/UserAuthHostBasedFactory.java
@@ -0,0 +1,86 @@
+/*
+ * 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.auth.hostbased;
+
+import java.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthHostBasedFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
+    public static final String NAME = HOST_BASED;
+
+    private List<NamedFactory<Signature>> factories;
+    private HostKeyIdentityProvider clientHostKeys;
+    private String clientUsername;
+    private String clientHostname;
+
+    public UserAuthHostBasedFactory() {
+        super(NAME);
+    }
+
+    @Override
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return factories;
+    }
+
+    @Override
+    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+        this.factories = factories;
+    }
+
+    public HostKeyIdentityProvider getClientHostKeys() {
+        return clientHostKeys;
+    }
+
+    public void setClientHostKeys(HostKeyIdentityProvider clientHostKeys) {
+        this.clientHostKeys = clientHostKeys;
+    }
+
+    public String getClientUsername() {
+        return clientUsername;
+    }
+
+    public void setClientUsername(String clientUsername) {
+        this.clientUsername = clientUsername;
+    }
+
+    public String getClientHostname() {
+        return clientHostname;
+    }
+
+    public void setClientHostname(String clientHostname) {
+        this.clientHostname = clientHostname;
+    }
+
+    @Override
+    public UserAuthHostBased create() {
+        UserAuthHostBased auth = new UserAuthHostBased(getClientHostKeys());
+        auth.setClientHostname(getClientHostname());
+        auth.setClientUsername(getClientUsername());
+        auth.setSignatureFactories(getSignatureFactories());
+        return auth;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
new file mode 100644
index 0000000..608f451
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractive.java
@@ -0,0 +1,306 @@
+/*
+ * 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.auth.keyboard;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sshd.client.ClientAuthenticationManager;
+import org.apache.sshd.client.auth.AbstractUserAuth;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+
+/**
+ * Manages a &quot;keyboard-interactive&quot; exchange according to
+ * <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthKeyboardInteractive extends AbstractUserAuth {
+    public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
+
+    public static final String INTERACTIVE_LANGUAGE_TAG = "kb-client-interactive-language-tag";
+
+    /*
+     * As per RFC-4256:
+     *
+     *      The language tag is deprecated and SHOULD be the empty string.  It
+     *      may be removed in a future revision of this specification.  Instead,
+     *      the server SHOULD select the language to be used based on the tags
+     *      communicated during key exchange
+     */
+    public static final String DEFAULT_INTERACTIVE_LANGUAGE_TAG = "";
+
+    public static final String INTERACTIVE_SUBMETHODS = "kb-client-interactive-sub-methods";
+
+    /*
+     * As per RFC-4256:
+     *
+     *      The submethods field is included so the user can give a hint of which
+     *      actual methods he wants to use.  It is a comma-separated list of
+     *      authentication submethods (software or hardware) that the user
+     *      prefers.  If the client has knowledge of the submethods preferred by
+     *      the user, presumably through a configuration setting, it MAY use the
+     *      submethods field to pass this information to the server.  Otherwise,
+     *      it MUST send the empty string.
+     *
+     *      The actual names of the submethods is something the user and the
+     *      server need to agree upon.
+     *
+     *      Server interpretation of the submethods field is implementation-
+     *      dependent.
+     */
+    public static final String DEFAULT_INTERACTIVE_SUBMETHODS = "";
+
+    private final AtomicBoolean requestPending = new AtomicBoolean(false);
+    private final AtomicInteger trialsCount = new AtomicInteger(0);
+    private Iterator<String> passwords;
+    private int maxTrials;
+
+    public UserAuthKeyboardInteractive() {
+        super(NAME);
+    }
+
+    @Override
+    public void init(ClientSession session, String service) throws Exception {
+        super.init(session, service);
+        passwords = PasswordIdentityProvider.Utils.iteratorOf(session);
+        maxTrials = PropertyResolverUtils.getIntProperty(session, ClientAuthenticationManager.PASSWORD_PROMPTS, ClientAuthenticationManager.DEFAULT_PASSWORD_PROMPTS);
+        ValidateUtils.checkTrue(maxTrials > 0, "Non-positive max. trials: %d", maxTrials);
+    }
+
+    @Override
+    protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
+        String name = getName();
+        if (requestPending.get()) {
+            if (log.isDebugEnabled()) {
+                log.debug("sendAuthDataRequest({})[{}] no reply for previous request for {}",
+                          session, service, name);
+            }
+            return false;
+        }
+
+        if (!verifyTrialsCount(session, service, SshConstants.SSH_MSG_USERAUTH_REQUEST, trialsCount.get(), maxTrials)) {
+            return false;
+        }
+
+        String username = session.getUsername();
+        String lang = getExchangeLanguageTag(session);
+        String subMethods = getExchangeSubMethods(session);
+        if (log.isDebugEnabled()) {
+            log.debug("sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST for {}: lang={}, methods={}",
+                      session, service, name, lang, subMethods);
+        }
+
+        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
+                            username.length() + service.length() + name.length()
+                          + GenericUtils.length(lang) + GenericUtils.length(subMethods)
+                          + Long.SIZE /* a bit extra for the lengths */);
+        buffer.putString(username);
+        buffer.putString(service);
+        buffer.putString(name);
+        buffer.putString(lang);
+        buffer.putString(subMethods);
+        requestPending.set(true);
+        session.writePacket(buffer);
+        return true;
+    }
+
+    @Override
+    protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
+        int cmd = buffer.getUByte();
+        if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST) {
+            throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
+                            + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
+        }
+
+        requestPending.set(false);
+
+        if (!verifyTrialsCount(session, service, cmd, trialsCount.incrementAndGet(), maxTrials)) {
+            return false;
+        }
+
+        String name = buffer.getString();
+        String instruction = buffer.getString();
+        String lang = buffer.getString();
+        int num = buffer.getInt();
+        if (log.isDebugEnabled()) {
+            log.debug("processAuthDataRequest({})[{}] SSH_MSG_USERAUTH_INFO_REQUEST name={}, instruction={}, language={}, num-prompts={}",
+                      session, service, name, instruction, lang, num);
+        }
+
+        String[] prompt = new String[num];
+        boolean[] echo = new boolean[num];
+        for (int i = 0; i < num; i++) {
+            // according to RFC4256: "The prompt field(s) MUST NOT be empty strings."
+            prompt[i] = buffer.getString();
+            echo[i] = buffer.getBoolean();
+        }
+
+        if (log.isTraceEnabled()) {
+            log.trace("processAuthDataRequest({})[{}] Prompt: {}", session, service, Arrays.toString(prompt));
+            log.trace("processAuthDataRequest({})[{}] Echo: {}", session, service, Arrays.toString(echo));
+        }
+
+        String[] rep = getUserResponses(name, instruction, lang, prompt, echo);
+        if (rep == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("processAuthDataRequest({})[{}] no responses for {}", session, service, name);
+            }
+            return false;
+        }
+
+        /*
+         * According to RFC4256:
+         *
+         *      If the num-responses field does not match the num-prompts
+         *      field in the request message, the server MUST send a failure
+         *      message.
+         *
+         * However it is the server's (!) responsibility to fail, so we only warn...
+         */
+        if (num != rep.length) {
+            log.warn("processAuthDataRequest({})[{}] Mismatched prompts ({}) vs. responses count ({})",
+                     session, service, num, rep.length);
+        }
+
+        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE, BufferUtils.clear(buffer));
+        buffer.putInt(rep.length);
+        for (int index = 0; index < rep.length; index++) {
+            String r = rep[index];
+            if (log.isTraceEnabled()) {
+                log.trace("processAuthDataRequest({})[{}] response #{}: {}", session, service, index + 1, r);
+            }
+            buffer.putString(r);
+        }
+
+        session.writePacket(buffer);
+        return true;
+    }
+
+    protected String getExchangeLanguageTag(ClientSession session) {
+        return PropertyResolverUtils.getStringProperty(session, INTERACTIVE_LANGUAGE_TAG, DEFAULT_INTERACTIVE_LANGUAGE_TAG);
+    }
+
+    protected String getExchangeSubMethods(ClientSession session) {
+        return PropertyResolverUtils.getStringProperty(session, INTERACTIVE_SUBMETHODS, DEFAULT_INTERACTIVE_SUBMETHODS);
+    }
+
+    protected String getCurrentPasswordCandidate() {
+        if ((passwords != null) && passwords.hasNext()) {
+            return passwords.next();
+        } else {
+            return null;
+        }
+    }
+
+    protected boolean verifyTrialsCount(ClientSession session, String service, int cmd, int nbTrials, int maxAllowed) {
+        if (log.isDebugEnabled()) {
+            log.debug("verifyTrialsCount({})[{}] cmd={} - {} out of {}",
+                      session, service, getAuthCommandName(cmd), nbTrials, maxAllowed);
+        }
+
+        return nbTrials <= maxAllowed;
+    }
+
+    /**
+     * @param name        The interaction name - may be empty
+     * @param instruction The instruction - may be empty
+     * @param lang        The language tag - may be empty
+     * @param prompt      The prompts - may be empty
+     * @param echo        Whether to echo the response for the prompt or not - same
+     *                    length as the prompts
+     * @return The response for each prompt - if {@code null} then the assumption
+     * is that some internal error occurred and no response is sent. <B>Note:</B>
+     * according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
+     * the number of responses should be <U>exactly</U> the same as the number
+     * of prompts. However, since it is the <U>server's</U> responsibility to
+     * enforce this we do not validate the response (other than logging it as
+     * a warning...)
+     */
+    protected String[] getUserResponses(String name, String instruction, String lang, String[] prompt, boolean[] echo) {
+        ClientSession session = getClientSession();
+        int num = GenericUtils.length(prompt);
+        if (num == 0) {
+            if (log.isDebugEnabled()) {
+                log.debug("getUserResponses({}) no prompts for interaction={}", session, name);
+            }
+            return GenericUtils.EMPTY_STRING_ARRAY;
+        }
+
+        String candidate = getCurrentPasswordCandidate();
+        if (useCurrentPassword(candidate, name, instruction, lang, prompt, echo)) {
+            if (log.isDebugEnabled()) {
+                log.debug("getUserResponses({}) use password candidate for interaction={}", session, name);
+            }
+            return new String[]{candidate};
+        }
+
+        UserInteraction ui = session.getUserInteraction();
+        if ((ui != null) && ui.isInteractionAllowed(session)) {
+            return ui.interactive(session, name, instruction, lang, prompt, echo);
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("getUserResponses({}) no user interaction for name={}", session, name);
+        }
+
+        return null;
+    }
+
+    protected boolean useCurrentPassword(String password, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
+        int num = GenericUtils.length(prompt);
+        if ((num != 1) || (password == null) || echo[0]) {
+            return false;
+        }
+
+        // check that prompt is something like "XXX password YYY:"
+        String value = GenericUtils.trimToEmpty(prompt[0]).toLowerCase();
+        int passPos = value.lastIndexOf("password");
+        if (passPos < 0) {  // no password keyword in prompt
+            return false;
+        }
+
+        int sepPos = value.lastIndexOf(':');
+        if (sepPos <= passPos) {    // no prompt separator or separator before the password keyword
+            return false;
+        }
+
+        return true;
+    }
+
+    public static String getAuthCommandName(int cmd) {
+        switch(cmd) {
+            case SshConstants.SSH_MSG_USERAUTH_REQUEST:
+                return "SSH_MSG_USERAUTH_REQUEST";
+            case SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST:
+                return "SSH_MSG_USERAUTH_INFO_REQUEST";
+            default:
+                return SshConstants.getCommandMessageName(cmd);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractiveFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
new file mode 100644
index 0000000..86bf005
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserAuthKeyboardInteractiveFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.auth.keyboard;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthKeyboardInteractiveFactory extends AbstractUserAuthFactory {
+    public static final String NAME = KB_INTERACTIVE;
+    public static final UserAuthKeyboardInteractiveFactory INSTANCE = new UserAuthKeyboardInteractiveFactory();
+
+    public UserAuthKeyboardInteractiveFactory() {
+        super(NAME);
+    }
+
+    @Override
+    public UserAuthKeyboardInteractive create() {
+        return new UserAuthKeyboardInteractive();
+    }
+}
\ No newline at end of file


[2/3] mina-sshd git commit: [SSHD-620] Add support for 'hostbased' authentication

Posted by lg...@apache.org.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserInteraction.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserInteraction.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserInteraction.java
new file mode 100644
index 0000000..5d0fddd
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/keyboard/UserInteraction.java
@@ -0,0 +1,110 @@
+/*
+ * 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.auth.keyboard;
+
+import org.apache.sshd.client.session.ClientSession;
+
+/**
+ * Interface used by the ssh client to communicate with the end user.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <a href="https://www.ietf.org/rfc/rfc4256.txt">RFC 4256</A>
+ */
+public interface UserInteraction {
+    /**
+     * A useful &quot;placeholder&quot; that indicates that no interaction is expected.
+     * <B>Note:</B> throws {@link IllegalStateException} is any of the interaction
+     * methods is called
+     */
+    UserInteraction NONE = new UserInteraction() {
+        @Override
+        public boolean isInteractionAllowed(ClientSession session) {
+            return false;
+        }
+
+        @Override
+        public void welcome(ClientSession session, String banner, String lang) {
+            // ignored
+        }
+
+        @Override
+        public String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
+            throw new IllegalStateException("interactive(" + session + ")[" + name + "] unexpected call");
+        }
+
+        @Override
+        public String getUpdatedPassword(ClientSession session, String prompt, String lang) {
+            throw new IllegalStateException("getUpdatedPassword(" + session + ")[" + prompt + "] unexpected call");
+        }
+
+        @Override
+        public String toString() {
+            return "NONE";
+        }
+    };
+
+    /**
+     *
+     * @param session The {@link ClientSession}
+     * @return {@code true} if user interaction allowed for this session
+     */
+    boolean isInteractionAllowed(ClientSession session);
+
+    /**
+     * Displays the welcome banner to the user.
+     *
+     * @param session The {@link ClientSession} through which the banner was received
+     * @param banner  The welcome banner
+     * @param lang    The banner language code - may be empty
+     */
+    void welcome(ClientSession session, String banner, String lang);
+
+    /**
+     * Invoked when &quot;keyboard-interactive&quot; authentication mechanism
+     * is used in order to provide responses for the server's challenges
+     * (a.k.a. prompts)
+     *
+     * @param session     The {@link ClientSession} through which the request was received
+     * @param name        The interaction name (may be empty)
+     * @param instruction The instruction (may be empty)
+     * @param lang        The language for the data (may be empty)
+     * @param prompt      The prompts to be displayed (may be empty)
+     * @param echo        For each prompt whether to echo the user's response
+     * @return The replies - <B>Note:</B> the protocol states that the number
+     * of replies should be <U>exactly</U> the same as the number of prompts,
+     * however we do not enforce it since it is defined as the <U>server's</U>
+     * job to check and manage this violation.
+     */
+    String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo);
+
+    /**
+     * Invoked when the server returns an {@code SSH_MSG_USERAUTH_PASSWD_CHANGEREQ}
+     * response indicating that the password should be changed - e.g., expired or
+     * not strong enough (as per the server's policy).
+     *
+     * @param session The {@link ClientSession} through which the request was received
+     * @param prompt The server's prompt (may be empty)
+     * @param lang The prompt's language (may be empty)
+     * @return The password to use - if {@code null}/empty then no updated
+     * password was provided - thus failing the authentication via passwords
+     * (<B>Note:</B> authentication might still succeed via some other means -
+     * be it other passwords, public keys, etc...)
+     */
+    String getUpdatedPassword(ClientSession session, String prompt, String lang);
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/password/PasswordIdentityProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/password/PasswordIdentityProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/PasswordIdentityProvider.java
new file mode 100644
index 0000000..cd9e4f3
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/PasswordIdentityProvider.java
@@ -0,0 +1,146 @@
+/*
+ * 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.auth.password;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Supplier;
+import org.apache.sshd.common.util.Transformer;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface PasswordIdentityProvider {
+    PasswordIdentityProvider EMPTY_PASSWORDS_PROVIDER = new PasswordIdentityProvider() {
+        @Override
+        public Iterable<String> loadPasswords() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public String toString() {
+            return "EMPTY";
+        }
+    };
+
+    /**
+     * @return The currently available passwords - never {@code null}
+     */
+    Iterable<String> loadPasswords();
+
+    /**
+     * A helper class for password identity provider related operations
+     * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+     */
+    // CHECKSTYLE:OFF
+    final class Utils {
+    // CHECKSTYLE:ON
+        public static final Transformer<PasswordIdentityProvider, Iterable<String>> LOADER =
+            new Transformer<PasswordIdentityProvider, Iterable<String>>() {
+                @Override
+                public Iterable<String> transform(PasswordIdentityProvider p) {
+                    return (p == null) ? null : p.loadPasswords();
+                }
+            };
+
+        private Utils() {
+            throw new UnsupportedOperationException("No instance allowed");
+        }
+
+        public static Iterator<String> iteratorOf(ClientSession session) {
+            ValidateUtils.checkNotNull(session, "No session");
+            return iteratorOf(session.getRegisteredIdentities(), session.getPasswordIdentityProvider());
+        }
+
+        public static Iterator<String> iteratorOf(PasswordIdentityProvider identities, PasswordIdentityProvider passwords) {
+            return iteratorOf(resolvePasswordIdentityProvider(identities, passwords));
+        }
+
+        /**
+         * Resolves a non-{@code null} iterator of the available passwords
+         *
+         * @param provider The {@link PasswordIdentityProvider} - ignored if {@code null}
+         * @return A non-{@code null} iterator - which may be empty if no provider or no passwords
+         */
+        public static Iterator<String> iteratorOf(PasswordIdentityProvider provider) {
+            return GenericUtils.iteratorOf((provider == null) ? null : provider.loadPasswords());
+        }
+
+        public static PasswordIdentityProvider resolvePasswordIdentityProvider(PasswordIdentityProvider identities, PasswordIdentityProvider passwords) {
+            if ((passwords == null) || (identities == passwords)) {
+                return identities;
+            } else if (identities == null) {
+                return passwords;
+            } else {
+                return multiProvider(identities, passwords);
+            }
+        }
+
+        public static PasswordIdentityProvider multiProvider(PasswordIdentityProvider ... providers) {
+            return multiProvider(GenericUtils.isEmpty(providers) ? Collections.<PasswordIdentityProvider>emptyList() : Arrays.asList(providers));
+        }
+
+        public static PasswordIdentityProvider multiProvider(Collection<? extends PasswordIdentityProvider> providers) {
+            return wrap(iterableOf(providers));
+        }
+
+        public static Iterable<String> iterableOf(Collection<? extends PasswordIdentityProvider> providers) {
+            if (GenericUtils.isEmpty(providers)) {
+                return Collections.emptyList();
+            }
+
+            Collection<Supplier<Iterable<String>>> suppliers = new ArrayList<Supplier<Iterable<String>>>(providers.size());
+            for (final PasswordIdentityProvider p : providers) {
+                if (p == null) {
+                    continue;
+                }
+
+                suppliers.add(new Supplier<Iterable<String>>() {
+                    @Override
+                    public Iterable<String> get() {
+                        return p.loadPasswords();
+                    }
+                });
+            }
+
+            if (GenericUtils.isEmpty(suppliers)) {
+                return Collections.emptyList();
+            }
+
+            return GenericUtils.multiIterableSuppliers(suppliers);
+        }
+
+        public static PasswordIdentityProvider wrap(final Iterable<String> passwords) {
+            return new PasswordIdentityProvider() {
+                @Override
+                public Iterable<String> loadPasswords() {
+                    return passwords;
+                }
+            };
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPassword.java
new file mode 100644
index 0000000..3db61be
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPassword.java
@@ -0,0 +1,137 @@
+/*
+ * 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.auth.password;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Objects;
+
+import org.apache.sshd.client.auth.AbstractUserAuth;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+
+/**
+ * Implements the &quot;password&quot; authentication mechanism
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPassword extends AbstractUserAuth {
+    public static final String NAME = UserAuthPasswordFactory.NAME;
+
+    private Iterator<String> passwords;
+    private String current;
+
+    public UserAuthPassword() {
+        super(NAME);
+    }
+
+    @Override
+    public void init(ClientSession session, String service) throws Exception {
+        super.init(session, service);
+        passwords = PasswordIdentityProvider.Utils.iteratorOf(session);
+    }
+
+    @Override
+    protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
+        if ((passwords == null) || (!passwords.hasNext())) {
+            if (log.isDebugEnabled()) {
+                log.debug("sendAuthDataRequest({})[{}] no more passwords to send", session, service);
+            }
+
+            return false;
+        }
+
+        current = passwords.next();
+        String username = session.getUsername();
+        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST,
+                            username.length() + service.length() + getName().length() + current.length() + Integer.SIZE);
+        sendPassword(buffer, session, current, current);
+        return true;
+    }
+
+    @Override
+    protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
+        int cmd = buffer.getUByte();
+        if (cmd != SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
+            throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
+                            + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
+        }
+
+        String prompt = buffer.getString();
+        String lang = buffer.getString();
+        UserInteraction ui = session.getUserInteraction();
+        if ((ui != null) && ui.isInteractionAllowed(session)) {
+            String password = ui.getUpdatedPassword(session, prompt, lang);
+            if (GenericUtils.isEmpty(password)) {
+                if (log.isDebugEnabled()) {
+                    log.debug("processAuthDataRequest({})[{}] No updated password for prompt={}, lang={}",
+                              session, service, prompt, lang);
+                }
+            } else {
+                sendPassword(buffer, session, password, password);
+                return true;
+            }
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("processAuthDataRequest({})[{}] no UI for password change request for prompt={}, lang={}",
+                          session, service, prompt, lang);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Sends the password via a {@code SSH_MSG_USERAUTH_REQUEST} message.
+     * If old and new password are not the same then it requests a password
+     * modification from the server (which may be denied if the server does
+     * not support this feature).
+     *
+     * @param buffer The {@link Buffer} to re-use for sending the message
+     * @param session The target {@link ClientSession}
+     * @param oldPassword The previous password
+     * @param newPassword The new password
+     * @throws IOException If failed to send the message.
+     */
+    protected void sendPassword(Buffer buffer, ClientSession session, String oldPassword, String newPassword) throws IOException {
+        String username = session.getUsername();
+        String service = getService();
+        String name = getName();
+        boolean modified = !Objects.equals(oldPassword, newPassword);
+        if (log.isDebugEnabled()) {
+            log.debug("sendPassword({})[{}] send SSH_MSG_USERAUTH_REQUEST for {} - modified={}",
+                      session, service, name, modified);
+        }
+
+        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, BufferUtils.clear(buffer));
+        buffer.putString(username);
+        buffer.putString(service);
+        buffer.putString(name);
+        buffer.putBoolean(modified);
+        // see RFC-4252 section 8
+        buffer.putString(oldPassword);
+        if (modified) {
+            buffer.putString(newPassword);
+        }
+        session.writePacket(buffer);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPasswordFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPasswordFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPasswordFactory.java
new file mode 100644
index 0000000..b52206c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/password/UserAuthPasswordFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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.auth.password;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPasswordFactory extends AbstractUserAuthFactory {
+    public static final String NAME = PASSWORD;
+    public static final UserAuthPasswordFactory INSTANCE = new UserAuthPasswordFactory();
+
+    public UserAuthPasswordFactory() {
+        super(NAME);
+    }
+
+    @Override
+    public UserAuthPassword create() {
+        return new UserAuthPassword();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKey.java
new file mode 100644
index 0000000..95bec60
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKey.java
@@ -0,0 +1,178 @@
+/*
+ * 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.auth.pubkey;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuth;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+
+/**
+ * Implements the &quot;publickey&quot; authentication mechanism
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFactoriesManager {
+    public static final String NAME = UserAuthPublicKeyFactory.NAME;
+
+    private Iterator<PublicKeyIdentity> keys;
+    private PublicKeyIdentity current;
+    private List<NamedFactory<Signature>> factories;
+
+    public UserAuthPublicKey() {
+        this(null);
+    }
+
+    public UserAuthPublicKey(List<NamedFactory<Signature>> factories) {
+        super(NAME);
+        this.factories = factories; // OK if null/empty
+    }
+
+    @Override
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return factories;
+    }
+
+    @Override
+    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+        this.factories = factories;
+    }
+
+    @Override
+    public void init(ClientSession session, String service) throws Exception {
+        super.init(session, service);
+        releaseKeys();  // just making sure in case multiple calls to the method
+        keys = new UserAuthPublicKeyIterator(session, this);
+    }
+
+    @Override
+    protected boolean sendAuthDataRequest(ClientSession session, String service) throws Exception {
+        if ((keys == null) || (!keys.hasNext())) {
+            if (log.isDebugEnabled()) {
+                log.debug("sendAuthDataRequest({})[{}] no more keys to send", session, service);
+            }
+
+            return false;
+        }
+
+        current = keys.next();
+        if (log.isTraceEnabled()) {
+            log.trace("sendAuthDataRequest({})[{}] current key details: {}", session, service, current);
+        }
+
+        PublicKey key = current.getPublicKey();
+        String algo = KeyUtils.getKeyType(key);
+        String name = getName();
+        if (log.isDebugEnabled()) {
+            log.debug("sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST request {} type={} - fingerprint={}",
+                      session, service, name, algo, KeyUtils.getFingerPrint(key));
+        }
+        Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+        buffer.putString(session.getUsername());
+        buffer.putString(service);
+        buffer.putString(name);
+        buffer.putBoolean(false);
+        buffer.putString(algo);
+        buffer.putPublicKey(key);
+        session.writePacket(buffer);
+        return true;
+    }
+
+    @Override
+    protected boolean processAuthDataRequest(ClientSession session, String service, Buffer buffer) throws Exception {
+        int cmd = buffer.getUByte();
+        if (cmd != SshConstants.SSH_MSG_USERAUTH_PK_OK) {
+            throw new IllegalStateException("processAuthDataRequest(" + session + ")[" + service + "]"
+                    + " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
+        }
+
+        PublicKey key = current.getPublicKey();
+        String algo = KeyUtils.getKeyType(key);
+        String name = getName();
+        if (log.isDebugEnabled()) {
+            log.debug("processAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_PK_OK reply {} type={} - fingerprint={}",
+                      session, service, name, algo, KeyUtils.getFingerPrint(key));
+        }
+
+        String username = session.getUsername();
+        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, BufferUtils.clear(buffer));
+        buffer.putString(username);
+        buffer.putString(service);
+        buffer.putString(name);
+        buffer.putBoolean(true);
+        buffer.putString(algo);
+        buffer.putPublicKey(key);
+
+        byte[] id = session.getSessionId();
+        Buffer bs = new ByteArrayBuffer(id.length + username.length() + service.length() + name.length()
+            + algo.length() + ByteArrayBuffer.DEFAULT_SIZE + Long.SIZE, false);
+        bs.putBytes(id);
+        bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+        bs.putString(username);
+        bs.putString(service);
+        bs.putString(name);
+        bs.putBoolean(true);
+        bs.putString(algo);
+        bs.putPublicKey(key);
+
+        byte[] sig = current.sign(bs.getCompactData());
+        bs = new ByteArrayBuffer(algo.length() + sig.length + Long.SIZE, false);
+        bs.putString(algo);
+        bs.putBytes(sig);
+        buffer.putBytes(bs.array(), bs.rpos(), bs.available());
+
+        session.writePacket(buffer);
+        return true;
+    }
+
+    @Override
+    public void destroy() {
+        try {
+            releaseKeys();
+        } catch (IOException e) {
+            throw new RuntimeException("Failed (" + e.getClass().getSimpleName() + ") to close agent: " + e.getMessage(), e);
+        }
+
+        super.destroy(); // for logging
+    }
+
+    protected void releaseKeys() throws IOException {
+        try {
+            if (keys instanceof Closeable) {
+                if (log.isTraceEnabled()) {
+                    log.trace("releaseKeys({}) closing {}", getClientSession(), keys);
+                }
+                ((Closeable) keys).close();
+            }
+        } finally {
+            keys = null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyFactory.java
new file mode 100644
index 0000000..176df0a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/pubkey/UserAuthPublicKeyFactory.java
@@ -0,0 +1,73 @@
+/*
+ * 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.auth.pubkey;
+
+import java.util.List;
+
+import org.apache.sshd.client.auth.AbstractUserAuthFactory;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactoriesManager;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKeyFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
+    public static final String NAME = PUBLIC_KEY;
+    public static final UserAuthPublicKeyFactory INSTANCE = new UserAuthPublicKeyFactory() {
+        @Override
+        public List<NamedFactory<Signature>> getSignatureFactories() {
+            return null;
+        }
+
+        @Override
+        public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+            if (!GenericUtils.isEmpty(factories)) {
+                throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
+            }
+        }
+    };
+
+    private List<NamedFactory<Signature>> factories;
+
+    public UserAuthPublicKeyFactory() {
+        this(null);
+    }
+
+    public UserAuthPublicKeyFactory(List<NamedFactory<Signature>> factories) {
+        super(NAME);
+        this.factories = factories; // OK if null/empty
+    }
+
+    @Override
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return factories;
+    }
+
+    @Override
+    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
+        this.factories = factories;
+    }
+
+    @Override
+    public UserAuthPublicKey create() {
+        return new UserAuthPublicKey(getSignatureFactories());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
index d5b6066..3e5c12e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
@@ -27,9 +27,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.apache.sshd.client.ClientFactoryManager;
 import org.apache.sshd.client.auth.AuthenticationIdentitiesProvider;
-import org.apache.sshd.client.auth.PasswordIdentityProvider;
 import org.apache.sshd.client.auth.UserAuth;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
+import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
 import org.apache.sshd.client.channel.ChannelDirectTcpip;
 import org.apache.sshd.client.channel.ChannelExec;
 import org.apache.sshd.client.channel.ChannelSubsystem;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
index 521da96..f13f8f7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
@@ -27,7 +27,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.client.ClientAuthenticationManager;
 import org.apache.sshd.client.auth.UserAuth;
-import org.apache.sshd.client.auth.UserInteraction;
+import org.apache.sshd.client.auth.keyboard.UserInteraction;
 import org.apache.sshd.client.future.AuthFuture;
 import org.apache.sshd.client.future.DefaultAuthFuture;
 import org.apache.sshd.common.NamedFactory;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java b/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
index e9b8856..8b8a507 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
@@ -18,11 +18,21 @@
  */
 package org.apache.sshd.common;
 
+import java.net.Inet4Address;
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
 import java.net.SocketAddress;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.List;
 import java.util.Objects;
 
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.NumberUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 
 /**
@@ -45,14 +55,39 @@ import org.apache.sshd.common.util.ValidateUtils;
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public class SshdSocketAddress extends SocketAddress {
+    public static final String LOCALHOST_NAME = "localhost";
     public static final String LOCALHOST_IP = "127.0.0.1";
     public static final String IP_ANYADDR = "0.0.0.0";
 
+    // 10.0.0.0 - 10.255.255.255
+    public static final String PRIVATE_CLASS_A_PREFIX = "10.";
+    // 172.16.0.0 - 172.31.255.255
+    public static final String PRIVATE_CLASS_B_PREFIX = "172.";
+    // 192.168.0.0 - 192.168.255.255
+    public static final String PRIVATE_CLASS_C_PREFIX = "192.168.";
+    // 100.64.0.0 - 100.127.255.255
+    public static final String CARRIER_GRADE_NAT_PREFIX = "100.";
+    // The IPv4 broadcast address
+    public static final String BROADCAST_ADDRESS = "255.255.255.255";
+
     /**
      * A dummy placeholder that can be used instead of {@code null}s
      */
     public static final SshdSocketAddress LOCALHOST_ADDRESS = new SshdSocketAddress(LOCALHOST_IP, 0);
 
+    /**
+     * Compares {@link InetAddress}-es according to their {@link InetAddress#getHostAddress()}
+     * value case <U>insensitive</U>
+     */
+    public static final Comparator<InetAddress> BY_HOST_ADDRESS = new Comparator<InetAddress>() {
+            @Override
+            public int compare(InetAddress a1, InetAddress a2) {
+                String n1 = GenericUtils.trimToEmpty(toAddressString(a1));
+                String n2 = GenericUtils.trimToEmpty(toAddressString(a2));
+                return String.CASE_INSENSITIVE_ORDER.compare(n1, n2);
+            }
+        };
+
     private static final long serialVersionUID = 6461645947151952729L;
 
     private final String hostName;
@@ -113,4 +148,268 @@ public class SshdSocketAddress extends SocketAddress {
     public int hashCode() {
         return Objects.hashCode(getHostName()) + getPort();
     }
+
+
+    /**
+     * Returns the first external network address assigned to this
+     * machine or null if one is not found.
+     * @return Inet4Address associated with an external interface
+     * DevNote:  We actually return InetAddress here, as Inet4Addresses are final and cannot be mocked.
+     */
+    public static InetAddress getFirstExternalNetwork4Address() {
+        List<? extends InetAddress> addresses = getExternalNetwork4Addresses();
+        return (GenericUtils.size(addresses) > 0) ? addresses.get(0) : null;
+    }
+
+    /**
+     * @return a {@link List} of local network addresses which are not multicast
+     * or localhost sorted according to {@link #BY_HOST_ADDRESS}
+     */
+    public static List<InetAddress> getExternalNetwork4Addresses() {
+        List<InetAddress> addresses = new ArrayList<InetAddress>();
+        try {
+            for (Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); (nets != null) && nets.hasMoreElements();) {
+                NetworkInterface netint = nets.nextElement();
+                /* TODO - uncomment when 1.5 compatibility no longer required
+                if (!netint.isUp()) {
+                    continue;    // ignore non-running interfaces
+                }
+                */
+
+                for (Enumeration<InetAddress> inetAddresses = netint.getInetAddresses(); (inetAddresses != null) && inetAddresses.hasMoreElements();) {
+                    InetAddress inetAddress = inetAddresses.nextElement();
+                    if (isValidHostAddress(inetAddress)) {
+                        addresses.add(inetAddress);
+                    }
+                }
+            }
+        } catch (SocketException e) {
+            // swallow
+        }
+
+        if (GenericUtils.size(addresses) > 1) {
+            Collections.sort(addresses, BY_HOST_ADDRESS);
+        }
+
+        return addresses;
+    }
+
+    /**
+     * @param addr The {@link InetAddress} to be verified
+     * @return <P><code>true</code> if the address is:</P></BR>
+     * <UL>
+     *         <LI>Not <code>null</code></LI>
+     *         <LI>An {@link Inet4Address}</LI>
+     *         <LI>Not link local</LI>
+     *         <LI>Not a multicast</LI>
+     *         <LI>Not a loopback</LI>
+     * </UL>
+     * @see InetAddress#isLinkLocalAddress()
+     * @see InetAddress#isMulticastAddress()
+     * @see InetAddress#isMulticastAddress()
+     */
+    public static boolean isValidHostAddress(InetAddress addr) {
+        if (addr == null) {
+            return false;
+        }
+
+        if (addr.isLinkLocalAddress()) {
+            return false;
+        }
+
+        if (addr.isMulticastAddress()) {
+            return false;
+        }
+
+        if (!(addr instanceof Inet4Address)) {
+            return false;
+        }
+
+        if (isLoopback(addr)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * @param addr The {@link InetAddress} to be considered
+     * @return <code>true</code> if the address is a loopback one.
+     * <B>Note:</B> if {@link InetAddress#isLoopbackAddress()}
+     * returns <code>false</code> the address <U>string</U> is checked
+     * @see #toAddressString(InetAddress)
+     * @see #isLoopback(String)
+     */
+    public static boolean isLoopback(InetAddress addr) {
+        if (addr == null) {
+            return false;
+        }
+
+        if (addr.isLoopbackAddress()) {
+            return true;
+        }
+
+        String ip = toAddressString(addr);
+        return isLoopback(ip);
+    }
+
+    /**
+     * @param ip IP value to be tested
+     * @return <code>true</code> if the IP is &quot;localhost&quot; or
+     * &quot;127.x.x.x&quot;.
+     */
+    public static boolean isLoopback(String ip) {
+        if (GenericUtils.isEmpty(ip)) {
+            return false;
+        }
+
+        if (LOCALHOST_NAME.equals(ip) || LOCALHOST_IP.equals(ip)) {
+            return true;
+        }
+
+        String[] values = GenericUtils.split(ip, '.');
+        if (GenericUtils.length(values) != 4) {
+            return false;
+        }
+
+        for (int index = 0; index < values.length; index++) {
+            String val = values[index];
+            if (!isValidIPv4AddressComponent(val)) {
+                return false;
+            }
+
+            if (index == 0) {
+                int number = Integer.parseInt(val);
+                if (number != 127) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public static String toAddressString(InetAddress addr) {
+        String ip = (addr == null) ? null : addr.toString();
+        if (GenericUtils.isEmpty(ip)) {
+            return null;
+        } else {
+            return ip.replaceAll(".*/", "");
+        }
+    }
+
+    public static final boolean isIPv4Address(String addr) {
+        if (GenericUtils.isEmpty(addr)) {
+            return false;
+        }
+
+        String[] comps = GenericUtils.split(addr, '.');
+        if (GenericUtils.length(comps) != 4) {
+            return false;
+        }
+
+        for (String c : comps) {
+            if (!isValidIPv4AddressComponent(c)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Checks if the address is one of the allocated private blocks
+     * @param addr The address string
+     * @return {@code true} if this is one of the allocated private
+     * blocks. <B>Note:</B> it assumes that the address string is
+     * indeed an IPv4 address
+     * @see #isIPv4Address(String)
+     * @see #PRIVATE_CLASS_A_PREFIX
+     * @see #PRIVATE_CLASS_B_PREFIX
+     * @see #PRIVATE_CLASS_C_PREFIX
+     * @see <A HREF="http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces">Wiki page</A>
+     */
+    public static final boolean isPrivateIPv4Address(String addr) {
+        if (GenericUtils.isEmpty(addr)) {
+            return false;
+        }
+
+        if (addr.startsWith(PRIVATE_CLASS_A_PREFIX) || addr.startsWith(PRIVATE_CLASS_C_PREFIX)) {
+            return true;
+        }
+
+        // for 172.x.x.x we need further checks
+        if (!addr.startsWith(PRIVATE_CLASS_B_PREFIX)) {
+            return false;
+        }
+
+        int nextCompPos = addr.indexOf('.', PRIVATE_CLASS_B_PREFIX.length());
+        if (nextCompPos <= PRIVATE_CLASS_B_PREFIX.length()) {
+            return false;
+        }
+
+        String value = addr.substring(PRIVATE_CLASS_B_PREFIX.length(), nextCompPos);
+        if (!isValidIPv4AddressComponent(value)) {
+            return false;
+        }
+
+        int v = Integer.parseInt(value);
+        return (v >= 16) && (v <= 31);
+    }
+
+    /**
+     * @param addr The address to be checked
+     * @return {@code true} if the address is in the 100.64.0.0/10 range
+     * @see <A HREF="http://tools.ietf.org/html/rfc6598">RFC6598</A>
+     */
+    public static final boolean isCarrierGradeNatIPv4Address(String addr) {
+        if (GenericUtils.isEmpty(addr)) {
+            return false;
+        }
+
+        if (!addr.startsWith(CARRIER_GRADE_NAT_PREFIX)) {
+            return false;
+        }
+
+        int nextCompPos = addr.indexOf('.', CARRIER_GRADE_NAT_PREFIX.length());
+        if (nextCompPos <= CARRIER_GRADE_NAT_PREFIX.length()) {
+            return false;
+        }
+
+        String value = addr.substring(CARRIER_GRADE_NAT_PREFIX.length(), nextCompPos);
+        if (!isValidIPv4AddressComponent(value)) {
+            return false;
+        }
+
+        int v = Integer.parseInt(value);
+        return (v >= 64) && (v <= 127);
+    }
+
+    /**
+     * <P>Checks if the provided argument is a valid IPv4 address component:</P></BR>
+     * <UL>
+     *     <LI>Not {@code null}/empty</LI>
+     *     <LI>Has at most 3 <U>digits</U></LI>
+     *     <LI>Its value is &le; 255</LI>
+     * </UL>
+     * @param c The {@link CharSequence} to be validate
+     * @return {@code true} if valid IPv4 address component
+     */
+    public static final boolean isValidIPv4AddressComponent(CharSequence c) {
+        if (GenericUtils.isEmpty(c) || (c.length() > 3)) {
+            return false;
+        }
+
+        char ch = c.charAt(0);
+        if ((ch < '0') || (ch > '9')) {
+            return false;
+        }
+
+        if (!NumberUtils.isIntegerNumber(c)) {
+            return false;
+        }
+
+        int v = Integer.parseInt(c.toString());
+        return (v >= 0) && (v <= 255);
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java
index f2b2a30..9b632e7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/auth/UserAuthMethodFactory.java
@@ -43,5 +43,10 @@ public interface UserAuthMethodFactory<M> extends NamedFactory<M> {
      * Keyboard interactive authentication method
      */
     String KB_INTERACTIVE = "keyboard-interactive";
+
+    /**
+     * Host-based authentication method
+     */
+    String HOST_BASED = "hostbased";
 }
 //CHECKSTYLE:ON

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java
index 0c61c03..b859386 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/NumberUtils.java
@@ -274,12 +274,40 @@ public final class NumberUtils {
         if (len <= 0) {
             return Collections.emptyList();
         }
-    
+
         List<Integer> l = new ArrayList<>(len);
         for (int v : values) {
             l.add(Integer.valueOf(v));
         }
-    
+
         return l;
     }
+
+    /**
+     * Checks if optional sign and all others are '0'-'9'
+     * @param cs The {@link CharSequence} to check
+     * @return {@code true} if valid integer number
+     */
+    public static boolean isIntegerNumber(CharSequence cs) {
+        if (GenericUtils.isEmpty(cs)) {
+            return false;
+        }
+
+        for (int index = 0; index < cs.length(); index++) {
+            char c = cs.charAt(0);
+            if ((c >= '0') && (c <= '9')) {
+                continue;
+            }
+
+            if ((c == '+') || (c == '-')) {
+                if (index == 0) {
+                    continue;
+                }
+            }
+
+            return false;
+        }
+
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
index 4ab6389..03efdfb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/SecurityUtils.java
@@ -34,6 +34,7 @@ import java.security.MessageDigest;
 import java.security.NoSuchProviderException;
 import java.security.SecureRandom;
 import java.security.Signature;
+import java.security.cert.CertificateFactory;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -592,4 +593,15 @@ public final class SecurityUtils {
             return Signature.getInstance(algorithm, providerName);
         }
     }
+
+    public static synchronized CertificateFactory getCertificateFactory(String type) throws GeneralSecurityException {
+        register();
+
+        String providerName = getSecurityProvider();
+        if (GenericUtils.isEmpty(providerName)) {
+            return CertificateFactory.getInstance(type);
+        } else {
+            return CertificateFactory.getInstance(type, providerName);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
index 99c075a..de6eef0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
@@ -26,14 +26,15 @@ import java.util.List;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.server.auth.UserAuth;
-import org.apache.sshd.server.auth.UserAuthKeyboardInteractiveFactory;
-import org.apache.sshd.server.auth.UserAuthPasswordFactory;
-import org.apache.sshd.server.auth.UserAuthPublicKeyFactory;
 import org.apache.sshd.server.auth.gss.GSSAuthenticator;
 import org.apache.sshd.server.auth.gss.UserAuthGSSFactory;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
 import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
+import org.apache.sshd.server.auth.keyboard.UserAuthKeyboardInteractiveFactory;
 import org.apache.sshd.server.auth.password.PasswordAuthenticator;
+import org.apache.sshd.server.auth.password.UserAuthPasswordFactory;
 import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.server.auth.pubkey.UserAuthPublicKeyFactory;
 
 /**
  * Holds providers and helpers related to the server side authentication process
@@ -67,7 +68,7 @@ public interface ServerAuthenticationManager {
      * {@code null}), then client authentication requests based on keys will be
      * rejected.
      *
-     * @return the <code>PublickeyAuthenticator</code> or {@code null}
+     * @return the {@link PublickeyAuthenticator} or {@code null}
      */
     PublickeyAuthenticator getPublickeyAuthenticator();
     void setPasswordAuthenticator(PasswordAuthenticator passwordAuthenticator);
@@ -78,7 +79,7 @@ public interface ServerAuthenticationManager {
      * {@code null}), then client authentication requests based on passwords
      * will be rejected.
      *
-     * @return the <code>PasswordAuthenticator</code> or {@code null}
+     * @return the {@link PasswordAuthenticator} or {@code null}
      */
     PasswordAuthenticator getPasswordAuthenticator();
     void setPublickeyAuthenticator(PublickeyAuthenticator publickeyAuthenticator);
@@ -100,11 +101,21 @@ public interface ServerAuthenticationManager {
      * {@code null}), then client authentication requests based on gssapi
      * will be rejected.
      *
-     * @return the <code>GSSAuthenticator</code> or {@code null}
+     * @return the {@link GSSAuthenticator} or {@code null}
      */
     GSSAuthenticator getGSSAuthenticator();
     void setGSSAuthenticator(GSSAuthenticator gssAuthenticator);
 
+    /**
+     * Retrieve the {@code HostBasedAuthenticator} to be used by the SSH server. If
+     * no authenticator has been configured (i.e. this method returns {@code null}),
+     * then client authentication requests based on this method will be rejected.
+     *
+     * @return the {@link HostBasedAuthenticator} or {@code null}
+     */
+    HostBasedAuthenticator getHostBasedAuthenticator();
+    void setHostBasedAuthenticator(HostBasedAuthenticator hostBasedAuthenticator);
+
     // CHECKSTYLE:OFF
     final class Utils {
     // CHECKSTYLE:ON

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/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 9fc121e..2c63f26 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
@@ -46,6 +46,7 @@ import org.apache.sshd.common.util.SecurityUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.server.auth.UserAuth;
 import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
 import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
 import org.apache.sshd.server.auth.password.PasswordAuthenticator;
 import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticator;
@@ -116,6 +117,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
     private PasswordAuthenticator passwordAuthenticator;
     private PublickeyAuthenticator publickeyAuthenticator;
     private KeyboardInteractiveAuthenticator interactiveAuthenticator;
+    private HostBasedAuthenticator hostBasedAuthenticator;
     private GSSAuthenticator gssAuthenticator;
 
     public SshServer() {
@@ -229,6 +231,16 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
     }
 
     @Override
+    public HostBasedAuthenticator getHostBasedAuthenticator() {
+        return hostBasedAuthenticator;
+    }
+
+    @Override
+    public void setHostBasedAuthenticator(HostBasedAuthenticator hostBasedAuthenticator) {
+        this.hostBasedAuthenticator = hostBasedAuthenticator;
+    }
+
+    @Override
     public void setTcpipForwardingFilter(ForwardingFilter forwardingFilter) {
         this.tcpipForwardingFilter = forwardingFilter;
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
deleted file mode 100644
index 9639929..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.server.auth;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.server.auth.keyboard.InteractiveChallenge;
-import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
-import org.apache.sshd.server.session.ServerSession;
-
-/**
- * Issue a &quot;keyboard-interactive&quot; command according to <A HREF="https://www.ietf.org/rfc/rfc4256.txt">RFC4256</A>
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthKeyboardInteractive extends AbstractUserAuth {
-    public static final String NAME = UserAuthKeyboardInteractiveFactory.NAME;
-
-    public UserAuthKeyboardInteractive() {
-        super(NAME);
-    }
-
-    @Override
-    protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
-        ServerSession session = getServerSession();
-        String username = getUsername();
-        KeyboardInteractiveAuthenticator auth = session.getKeyboardInteractiveAuthenticator();
-        if (init) {
-            String lang = buffer.getString();
-            String subMethods = buffer.getString();
-            if (auth == null) {
-                if (log.isDebugEnabled()) {
-                    log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive authenticator to generate challenge",
-                              username, session, subMethods, lang);
-                }
-                return false;
-            }
-
-            InteractiveChallenge challenge = auth.generateChallenge(session, getUsername(), lang, subMethods);
-            if (challenge == null) {
-                if (log.isDebugEnabled()) {
-                    log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive challenge generated",
-                              username, session, subMethods, lang);
-                }
-                return false;
-            }
-
-            if (log.isDebugEnabled()) {
-                log.debug("doAuth({}@{})[methods={}, lang={}] challenge name={}, instruction={}, lang={}, num. prompts={}",
-                          username, session, subMethods, lang,
-                          challenge.getInteractionName(), challenge.getInteractionInstruction(),
-                          challenge.getLanguageTag(), GenericUtils.size(challenge.getPrompts()));
-            }
-
-            // Prompt for password
-            buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, BufferUtils.clear(buffer));
-            challenge.append(buffer);
-            session.writePacket(buffer);
-            return null;
-        } else {
-            int cmd = buffer.getUByte();
-            if (cmd != SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE) {
-                throw new SshException("Received unexpected message: " + SshConstants.getCommandMessageName(cmd));
-            }
-
-            int num = buffer.getInt();
-            List<String> responses = (num <= 0) ? Collections.<String>emptyList() : new ArrayList<String>(num);
-            for (int index = 0; index < num; index++) {
-                String value = buffer.getString();
-                if (log.isTraceEnabled()) {
-                    log.trace("doAuth({}@{}) response #{}: {}", username, session, index + 1, value);
-                }
-                responses.add(value);
-            }
-
-            if (auth == null) {
-                if (log.isDebugEnabled()) {
-                    log.debug("doAuth({}@{}) no interactive authenticator to validate {} responses",
-                              username, session, num);
-                }
-                return false;
-            }
-
-            boolean authed = auth.authenticate(session, username, responses);
-            if (log.isDebugEnabled()) {
-                log.debug("doAuth({}@{}) authenticate {} responses result: {}",
-                          username, session, num, authed);
-            }
-
-            return authed;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractiveFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractiveFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractiveFactory.java
deleted file mode 100644
index 41defa0..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractiveFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.server.auth;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthKeyboardInteractiveFactory extends AbstractUserAuthFactory {
-    public static final String NAME = KB_INTERACTIVE;
-    public static final UserAuthKeyboardInteractiveFactory INSTANCE = new UserAuthKeyboardInteractiveFactory();
-
-    public UserAuthKeyboardInteractiveFactory() {
-        super(NAME);
-    }
-
-    @Override
-    public UserAuth create() {
-        return new UserAuthKeyboardInteractive();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java
index d1290b8..e42db13 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNoneFactory.java
@@ -30,7 +30,7 @@ public class UserAuthNoneFactory extends AbstractUserAuthFactory {
     }
 
     @Override
-    public UserAuth create() {
+    public UserAuthNone create() {
         return new UserAuthNone();
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
deleted file mode 100644
index b0e72d4..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.server.auth;
-
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.server.auth.password.PasswordAuthenticator;
-import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
-import org.apache.sshd.server.session.ServerSession;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPassword extends AbstractUserAuth {
-    public static final String NAME = UserAuthPasswordFactory.NAME;
-
-    public UserAuthPassword() {
-        super(NAME);
-    }
-
-    @Override
-    public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
-        ValidateUtils.checkTrue(init, "Instance not initialized");
-
-        boolean newPassword = buffer.getBoolean();
-        String password = buffer.getString();
-        if (newPassword) {
-            return handleClientPasswordChangeRequest(buffer, getServerSession(), getUsername(), password, buffer.getString());
-        } else {
-            return checkPassword(buffer, getServerSession(), getUsername(), password);
-        }
-    }
-
-    /**
-     * Invokes the configured {@link PasswordAuthenticator} and returns the result.
-     * If {@link PasswordChangeRequiredException} thrown by the authenticator then
-     * {@link #handleServerPasswordChangeRequest(Buffer, ServerSession, String, String, PasswordChangeRequiredException)}
-     * is invoked
-     *
-     * @param buffer   The received {@link Buffer} to be re-used if need to send
-     *                 a password change request
-     * @param session  The {@link ServerSession} through which the request was received
-     * @param username The username
-     * @param password The password
-     * @return The authentication result - if {@code null} then exception was handled
-     * internally and authentication is still in progress
-     * @throws Exception If internal error during authentication (exception for
-     * {@link PasswordChangeRequiredException} which is handled internally)
-     * @see #handleServerPasswordChangeRequest(Buffer, ServerSession, String, String, PasswordChangeRequiredException)
-     */
-    protected Boolean checkPassword(Buffer buffer, ServerSession session, String username, String password) throws Exception {
-        PasswordAuthenticator auth = session.getPasswordAuthenticator();
-        if (auth == null) {
-            if (log.isDebugEnabled()) {
-                log.debug("checkPassword({}) no password authenticator", session);
-            }
-            return false;
-        }
-
-        try {
-            boolean authed = auth.authenticate(username, password, session);
-            if (log.isDebugEnabled()) {
-                log.debug("checkPassword({}) authentication result: {}", session, authed);
-            }
-            return authed;
-        } catch (PasswordChangeRequiredException e) {
-            if (log.isDebugEnabled()) {
-                log.debug("checkPassword({}) password change required: {}", session, e.getMessage());
-            }
-            return handleServerPasswordChangeRequest(buffer, session, username, password, e);
-        }
-    }
-
-    /**
-     * Invoked when the client sends a {@code SSH_MSG_USERAUTH_REQUEST} indicating
-     * a password change. Throws {@link UnsupportedOperationException} by default
-     *
-     * @param buffer The {@link Buffer} to re-use in order to respond
-     * @param session The associated {@link ServerSession}
-     * @param username The username
-     * @param oldPassword The old password
-     * @param newPassword The new password
-     * @return Password change and authentication result - {@code null} means
-     * authentication incomplete - i.e., handler has sent some extra query.
-     * @throws Exception If failed to handle the request.
-     */
-    protected Boolean handleClientPasswordChangeRequest(
-            Buffer buffer, ServerSession session, String username, String oldPassword, String newPassword)
-                        throws Exception {
-        throw new UnsupportedOperationException("Password change not supported");
-    }
-
-    /**
-     * Invoked by {@link #checkPassword(Buffer, ServerSession, String, String)}
-     * when a {@link PasswordChangeRequiredException} was thrown by the authenticator.
-     * By default it re-throws the original exception.
-     *
-     * @param buffer   The received {@link Buffer} to be re-used if need to send
-     *                 a password change request
-     * @param session  The {@link ServerSession} through which the request was received
-     * @param username The username
-     * @param password The (rejected) password
-     * @param e        The original thrown exception
-     * @return {@code null} by default to indicate incomplete authentication
-     * @throws Exception If failed to dispatch the message
-     */
-    protected Boolean handleServerPasswordChangeRequest(
-            Buffer buffer, ServerSession session, String username, String password, PasswordChangeRequiredException e)
-                throws Exception {
-        String prompt = e.getPrompt();
-        String lang = e.getLanguage();
-        if (log.isDebugEnabled()) {
-            log.debug("handlePasswordChangeRequest({}) password change required - prompt={}, lang={}",
-                      session, prompt, lang);
-        }
-
-        buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, buffer);
-        buffer.putString(prompt);
-        buffer.putString(lang);
-        session.writePacket(buffer);
-        return null;    // authentication incomplete
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPasswordFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPasswordFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPasswordFactory.java
deleted file mode 100644
index e402912..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPasswordFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.server.auth;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPasswordFactory extends AbstractUserAuthFactory {
-    public static final String NAME = PASSWORD;
-    public static final UserAuthPasswordFactory INSTANCE = new UserAuthPasswordFactory();
-
-    public UserAuthPasswordFactory() {
-        super(NAME);
-    }
-
-    @Override
-    public UserAuth create() {
-        return new UserAuthPassword();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
deleted file mode 100644
index f9a93ec..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.server.auth;
-
-import java.security.PublicKey;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesManager;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
-import org.apache.sshd.server.session.ServerSession;
-
-/**
- * TODO Add javadoc
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPublicKey extends AbstractUserAuth implements SignatureFactoriesManager {
-    public static final String NAME = UserAuthPublicKeyFactory.NAME;
-
-    private List<NamedFactory<Signature>> factories;
-
-    public UserAuthPublicKey() {
-        this(null);
-    }
-
-    public UserAuthPublicKey(List<NamedFactory<Signature>> factories) {
-        super(NAME);
-        this.factories = factories; // OK if null/empty
-    }
-
-    @Override
-    public List<NamedFactory<Signature>> getSignatureFactories() {
-        return factories;
-    }
-
-    @Override
-    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
-        this.factories = factories;
-    }
-
-    @Override
-    public Boolean doAuth(Buffer buffer, boolean init) throws Exception {
-        ValidateUtils.checkTrue(init, "Instance not initialized");
-
-        boolean hasSig = buffer.getBoolean();
-        String alg = buffer.getString();
-        int oldLim = buffer.wpos();
-        int oldPos = buffer.rpos();
-        int len = buffer.getInt();
-        buffer.wpos(buffer.rpos() + len);
-
-        ServerSession session = getServerSession();
-        String username = getUsername();
-        PublicKey key = buffer.getRawPublicKey();
-        Collection<NamedFactory<Signature>> factories =
-                ValidateUtils.checkNotNullAndNotEmpty(
-                        SignatureFactoriesManager.Utils.resolveSignatureFactories(this, session),
-                        "No signature factories for session=%s",
-                        session);
-        if (log.isDebugEnabled()) {
-            log.debug("doAuth({}@{}) verify key type={}, factories={}, fingerprint={}",
-                      username, session, alg, NamedResource.Utils.getNames(factories), KeyUtils.getFingerPrint(key));
-        }
-
-        Signature verifier = ValidateUtils.checkNotNull(
-                NamedFactory.Utils.create(factories, alg),
-                "No verifier located for algorithm=%s",
-                alg);
-        verifier.initVerifier(key);
-        buffer.wpos(oldLim);
-
-        byte[] sig = hasSig ? buffer.getBytes() : null;
-        PublickeyAuthenticator authenticator = session.getPublickeyAuthenticator();
-        if (authenticator == null) {
-            if (log.isDebugEnabled()) {
-                log.debug("doAuth({}@{}) key type={}, fingerprint={} - no authenticator",
-                          username, session, alg, KeyUtils.getFingerPrint(key));
-            }
-            return false;
-        }
-
-        boolean authed = authenticator.authenticate(username, key, session);
-        if (log.isDebugEnabled()) {
-            log.debug("doAuth({}@{}) key type={}, fingerprint={} - authentication result: {}",
-                      username, session, alg, KeyUtils.getFingerPrint(key), authed);
-        }
-        if (!authed) {
-            return Boolean.FALSE;
-        }
-
-        if (!hasSig) {
-            if (log.isDebugEnabled()) {
-                log.debug("doAuth({}@{}) send SSH_MSG_USERAUTH_PK_OK for key type={}, fingerprint={}",
-                           username, session, alg, KeyUtils.getFingerPrint(key));
-            }
-
-            Buffer buf = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PK_OK, BufferUtils.clear(buffer));
-            buf.putString(alg);
-            buf.putRawBytes(buffer.array(), oldPos, 4 + len);
-            session.writePacket(buf);
-            return null;
-        }
-
-        // verify signature
-        Buffer buf = new ByteArrayBuffer();
-        buf.putBytes(session.getKex().getH());
-        buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
-        buf.putString(username);
-        buf.putString(getService());
-        buf.putString(getName());
-        buf.putBoolean(true);
-        buf.putString(alg);
-        buffer.rpos(oldPos);
-        buffer.wpos(oldPos + 4 + len);
-        buf.putBuffer(buffer);
-        verifier.update(buf.array(), buf.rpos(), buf.available());
-        if (log.isTraceEnabled()) {
-            log.trace("doAuth({}@{}) key type={}, fingerprint={} - verification data={}",
-                      username, session, alg, KeyUtils.getFingerPrint(key), buf.printHex());
-            log.trace("doAuth({}@{}) key type={}, fingerprint={} - expected signature={}",
-                    username, session, alg, KeyUtils.getFingerPrint(key), BufferUtils.printHex(sig));
-        }
-
-        if (!verifier.verify(sig)) {
-            throw new Exception("Key verification failed");
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("doAuth({}@{}) key type={}, fingerprint={} - verified",
-                      username, session, alg, KeyUtils.getFingerPrint(key));
-        }
-
-        return Boolean.TRUE;
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKeyFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKeyFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKeyFactory.java
deleted file mode 100644
index 72b8519..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKeyFactory.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.server.auth;
-
-import java.util.List;
-
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesManager;
-import org.apache.sshd.common.util.GenericUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class UserAuthPublicKeyFactory extends AbstractUserAuthFactory implements SignatureFactoriesManager {
-    public static final String NAME = PUBLIC_KEY;
-    public static final UserAuthPublicKeyFactory INSTANCE = new UserAuthPublicKeyFactory() {
-        @Override
-        public List<NamedFactory<Signature>> getSignatureFactories() {
-            return null;
-        }
-
-        @Override
-        public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
-            if (!GenericUtils.isEmpty(factories)) {
-                throw new UnsupportedOperationException("Not allowed to change default instance signature factories");
-            }
-        }
-    };
-
-    private List<NamedFactory<Signature>> factories;
-
-    public UserAuthPublicKeyFactory() {
-        this(null);
-    }
-
-    public UserAuthPublicKeyFactory(List<NamedFactory<Signature>> factories) {
-        super(NAME);
-        this.factories = factories; // OK if null/empty
-    }
-
-    @Override
-    public List<NamedFactory<Signature>> getSignatureFactories() {
-        return factories;
-    }
-
-    @Override
-    public void setSignatureFactories(List<NamedFactory<Signature>> factories) {
-        this.factories = factories;
-    }
-
-    @Override
-    public UserAuth create() {
-        return new UserAuthPublicKey(getSignatureFactories());
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/AcceptAllHostBasedAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/AcceptAllHostBasedAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/AcceptAllHostBasedAuthenticator.java
new file mode 100644
index 0000000..ef49a31
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/AcceptAllHostBasedAuthenticator.java
@@ -0,0 +1,31 @@
+/*
+ * 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.server.auth.hostbased;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public final class AcceptAllHostBasedAuthenticator extends StaticHostBasedAuthenticator {
+    public static final AcceptAllHostBasedAuthenticator INSTANCE = new AcceptAllHostBasedAuthenticator();
+
+    private AcceptAllHostBasedAuthenticator() {
+        super(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/HostBasedAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/HostBasedAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/HostBasedAuthenticator.java
new file mode 100644
index 0000000..37d2d3d
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/HostBasedAuthenticator.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.server.auth.hostbased;
+
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * Invoked when &quot;hostbased&quot; authentication is used
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://www.ietf.org/rfc/rfc4252.txt">RFC 4252 - section 9</A>
+ */
+public interface HostBasedAuthenticator {
+    /**
+     * @param session        The {@link ServerSession} through which the request was received
+     * @param username       The username attempting to login
+     * @param clientHostKey  The remote client's host {@link PublicKey}
+     * @param clientHostName The reported remote client's host name
+     * @param clientUsername The remote client username
+     * @param certificates   Associated {@link X509Certificate}s - may be {@code null}/empty
+     * @return {@code true} whether authentication is allowed to proceed
+     */
+    boolean authenticate(ServerSession session, String username,
+            PublicKey clientHostKey, String clientHostName, String clientUsername, List<X509Certificate> certificates);
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/18335089/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/RejectAllHostBasedAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/RejectAllHostBasedAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/RejectAllHostBasedAuthenticator.java
new file mode 100644
index 0000000..8d5eb14
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/hostbased/RejectAllHostBasedAuthenticator.java
@@ -0,0 +1,31 @@
+/*
+ * 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.server.auth.hostbased;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public final class RejectAllHostBasedAuthenticator extends StaticHostBasedAuthenticator {
+    public static final RejectAllHostBasedAuthenticator INSTANCE = new RejectAllHostBasedAuthenticator();
+
+    private RejectAllHostBasedAuthenticator() {
+        super(false);
+    }
+}