You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2013/07/17 16:32:14 UTC

[1/4] git commit: [SSHD-195] Fix welcome banner implementation

Updated Branches:
  refs/heads/master 25995ffe4 -> a49dee379


[SSHD-195] Fix welcome banner implementation

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

Branch: refs/heads/master
Commit: 5bb836651ad5e805fd367f375a574f92d2085776
Parents: 25995ff
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 17 09:00:49 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 17 09:00:49 2013 +0200

----------------------------------------------------------------------
 .../apache/sshd/server/session/ServerSession.java   | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5bb83665/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index eead762..f095ed7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -66,7 +66,6 @@ public class ServerSession extends AbstractSession {
     private boolean allowMoreSessions = true;
     private final AgentForwardSupport agentForward;
     private final X11ForwardSupport x11Forward;
-    private String welcomeBanner = null;
 
     private HandshakingUserAuth currentAuth;
 
@@ -79,7 +78,6 @@ public class ServerSession extends AbstractSession {
         idleTimeout = getIntProperty(ServerFactoryManager.IDLE_TIMEOUT, idleTimeout);
         agentForward = new AgentForwardSupport(this);
         x11Forward = new X11ForwardSupport(this);
-        welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
         log.info("Session created from {}", ioSession.getRemoteAddress());
         sendServerIdentification();
         sendKexInit();
@@ -405,12 +403,6 @@ public class ServerSession extends AbstractSession {
                 
               } else {
                 log.debug("Unsupported authentication method '{}'", method);
-                if (welcomeBanner != null) {
-                    buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
-                    buffer.putString(welcomeBanner);
-                    buffer.putString("\n");
-                    writePacket(buffer);
-                }
               }
             } else {
               try {
@@ -451,6 +443,14 @@ public class ServerSession extends AbstractSession {
                     }
                 }
 
+                String welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
+                if (welcomeBanner != null) {
+                    buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
+                    buffer.putString(welcomeBanner);
+                    buffer.putString("\n");
+                    writePacket(buffer);
+                }
+
                 buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_SUCCESS, 0);
                 writePacket(buffer);
                 setState(State.Running);


[4/4] git commit: [SSHD-234] Support partial authentications on the server side

Posted by gn...@apache.org.
[SSHD-234] Support partial authentications on the server side

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

Branch: refs/heads/master
Commit: a49dee379f8dab72421595ca28ececfb0ce0b7b2
Parents: 1937ee8
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 17 16:31:48 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 17 16:31:48 2013 +0200

----------------------------------------------------------------------
 .../main/java/org/apache/sshd/SshServer.java    |   1 +
 .../sshd/client/session/ClientSessionImpl.java  |  12 +-
 .../apache/sshd/server/HandshakingUserAuth.java |  20 +-
 .../sshd/server/ServerFactoryManager.java       |  14 ++
 .../java/org/apache/sshd/server/UserAuth.java   |   2 +-
 .../apache/sshd/server/auth/UserAuthNone.java   |   2 +-
 .../sshd/server/auth/UserAuthPassword.java      |   7 +-
 .../sshd/server/auth/UserAuthPublicKey.java     |   6 +-
 .../sshd/server/auth/gss/UserAuthGSS.java       |  30 +--
 .../sshd/server/session/ServerSession.java      | 224 ++++++++++++-------
 .../org/apache/sshd/AuthenticationTest.java     | 161 +++++++++++++
 11 files changed, 353 insertions(+), 126 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
index b5c95b6..a8b4919 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
@@ -551,6 +551,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
                                                     
         SshServer sshd = SshServer.setUpDefaultServer();
         sshd.setPort(port);
+        sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD");
         if (SecurityUtils.isBouncyCastleRegistered()) {
             sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider("key.pem"));
         } else {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index 37f7175..2949403 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -85,7 +85,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
         return kex;
     }
 
-    public AuthFuture authAgent(String username) throws IOException {
+    public AuthFuture authAgent(String user) throws IOException {
         synchronized (lock) {
             if (closeFuture.isClosed()) {
                 throw new IllegalStateException("Session is closed");
@@ -104,7 +104,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
                 throw new IllegalStateException("Session is closed");
             }
             authFuture = new DefaultAuthFuture(lock);
-            userAuth = new UserAuthAgent(this, username);
+            userAuth = new UserAuthAgent(this, user);
             setState(State.UserAuth);
 
             switch (userAuth.next(null)) {
@@ -126,7 +126,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
         }
     }
 
-    public AuthFuture authPassword(String username, String password) throws IOException {
+    public AuthFuture authPassword(String user, String password) throws IOException {
         synchronized (lock) {
             if (closeFuture.isClosed()) {
                 throw new IllegalStateException("Session is closed");
@@ -142,7 +142,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
                 throw new IllegalStateException("Session is closed");
             }
             authFuture = new DefaultAuthFuture(lock);
-            userAuth = new UserAuthPassword(this, username, password);
+            userAuth = new UserAuthPassword(this, user, password);
             setState(State.UserAuth);
 
             switch (userAuth.next(null)) {
@@ -164,7 +164,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
         }
     }
 
-    public AuthFuture authPublicKey(String username, KeyPair key) throws IOException {
+    public AuthFuture authPublicKey(String user, KeyPair key) throws IOException {
         synchronized (lock) {
             if (closeFuture.isClosed()) {
                 throw new IllegalStateException("Session is closed");
@@ -180,7 +180,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
                 throw new IllegalStateException("Session is closed");
             }
             authFuture = new DefaultAuthFuture(lock);
-            userAuth = new UserAuthPublicKey(this, username, key);
+            userAuth = new UserAuthPublicKey(this, user, key);
             setState(State.UserAuth);
 
             switch (userAuth.next(null)) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
index 625f7ba..d0bf5d9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
@@ -31,34 +31,16 @@ import org.apache.sshd.server.session.ServerSession;
 public interface HandshakingUserAuth extends UserAuth {
 
     /**
-     * Set the service name from the original request.  This may be required for MIC verification later.
-     *
-     * @param service The service name
-     */
-
-    void setServiceName(String service);
-
-    /**
-     * Check whether a particular message is handled here.
-     *
-     * @param msg The message
-     * @return <code>true</code> if the message is handled
-     */
-
-    boolean handles(SshConstants.Message msg);
-
-    /**
      * Handle another step in the authentication process.
      *
      * @param session the current ssh session
-     * @param msg     The message type
      * @param buffer  the request buffer containing parameters specific to this request
      * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
      *         is not finished yet
      * @throws Exception if the authentication fails
      */
 
-    Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception;
+    Boolean next(ServerSession session, Buffer buffer) throws Exception;
 
     /**
      * Get a user name which has been derived from the handshaking process, or the intial name if

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
index 3f1e74b..f179a15 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
@@ -68,6 +68,20 @@ public interface ServerFactoryManager extends FactoryManager {
     public static final String WELCOME_BANNER = "welcome-banner";
 
     /**
+     * This key is used when configuring multi-step authentications.
+     * The value needs to be a blank separated list of comma separated list
+     * of authentication method names.
+     * For example, an argument of
+     * <code>publickey,password publickey,keyboard-interactive</code>
+     * would require the user to complete public key authentication,
+     * followed by either password or keyboard interactive authentication.
+     * Only methods that are next in one or more lists are offered at each
+     * stage, so for this example, it would not be possible to attempt
+     * password or keyboard-interactive authentication before public key.
+     */
+    public static final String AUTH_METHODS = "auth-methods";
+
+    /**
      * Retrieve the list of named factories for <code>UserAuth<code> objects.
      *
      * @return a list of named <code>UserAuth</code> factories, never <code>null</code>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
index 8afb799..0bb9940 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
@@ -42,6 +42,6 @@ public interface UserAuth {
      *          is not finished yet
      * @throws Exception if the authentication fails
      */
-    Boolean auth(ServerSession session, String username, Buffer buffer) throws Exception;
+    Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception;
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
index 0297cef..3d96c9e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
@@ -39,7 +39,7 @@ public class UserAuthNone implements UserAuth {
         }
     }
 
-    public Boolean auth(ServerSession session, String username, Buffer buffer) {
+    public Boolean auth(ServerSession session, String username, String service, Buffer buffer) {
         return true;
     }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/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
index 39c2f49..b2c60e2 100644
--- 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
@@ -19,6 +19,8 @@
 package org.apache.sshd.server.auth;
 
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.util.Buffer;
 import org.apache.sshd.server.PasswordAuthenticator;
 import org.apache.sshd.server.UserAuth;
@@ -40,7 +42,10 @@ public class UserAuthPassword implements UserAuth {
         }
     }
 
-    public Boolean auth(ServerSession session, String username, Buffer buffer) throws Exception {
+    public Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception {
+        if (!"ssh-connection".equals(service)) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Unsupported service '" + service + "'");
+        }
         boolean newPassword = buffer.getBoolean();
         if (newPassword) {
             throw new IllegalStateException("Password changes are not supported");

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/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
index cb7a907..f9349a7 100644
--- 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
@@ -25,6 +25,7 @@ import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.util.Buffer;
 import org.apache.sshd.server.PublickeyAuthenticator;
 import org.apache.sshd.server.UserAuth;
@@ -46,7 +47,10 @@ public class UserAuthPublicKey implements UserAuth {
         }
     }
 
-    public Boolean auth(ServerSession session, String username, Buffer buffer) throws Exception {
+    public Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception {
+        if (!"ssh-connection".equals(service)) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Unsupported service '" + service + "'");
+        }
         boolean hasSig = buffer.getBoolean();
         String alg = buffer.getString();
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
index afcca3a..02f2458 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
@@ -20,6 +20,7 @@ package org.apache.sshd.server.auth.gss;
 
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.util.Buffer;
 import org.apache.sshd.server.HandshakingUserAuth;
 import org.apache.sshd.server.UserAuth;
@@ -39,7 +40,6 @@ import org.slf4j.LoggerFactory;
  * <p/>
  * Several methods are available for overriding in specific circumstances.
  */
-
 public class UserAuthGSS implements HandshakingUserAuth {
 
     // Oids for the Kerberos 5 mechanism and principal
@@ -88,10 +88,11 @@ public class UserAuthGSS implements HandshakingUserAuth {
      * @throws Exception If something went wrong
      */
 
-    public Boolean auth(ServerSession sess, String user, Buffer buff) throws Exception {
+    public Boolean auth(ServerSession sess, String user, String service, Buffer buff) throws Exception {
         GSSAuthenticator auth = getAuthenticator(sess);
 
         this.user = user;
+        this.service = service;
 
         // Get mechanism count from buffer and look for Kerberos 5.
 
@@ -136,22 +137,11 @@ public class UserAuthGSS implements HandshakingUserAuth {
     }
 
     /**
-     * Set the service name from the original request.  This may be required for MIC verification later.
-     *
-     * @param service The service name
-     */
-
-    public void setServiceName(String service) {
-        this.service = service;
-    }
-
-    /**
      * Check whether a particular message is handled here.
      *
      * @param msg The message
      * @return <code>true</code> if the message is handled
      */
-
     public boolean handles(SshConstants.Message msg) {
         return msg == SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE || msg == SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC && ctxt.isEstablished();
     }
@@ -165,8 +155,13 @@ public class UserAuthGSS implements HandshakingUserAuth {
      *         is not finished yet
      * @throws Exception if the authentication fails
      */
+    public Boolean next(ServerSession session, Buffer buffer) throws Exception {
+
+        SshConstants.Message msg = buffer.getCommand();
+        if (!handles(msg)) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Packet not supported by user authentication method");
+        }
 
-    public Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception {
         GSSAuthenticator auth = getAuthenticator(session);
 
         log.debug("In krb5.next: msg = " + msg);
@@ -229,7 +224,7 @@ public class UserAuthGSS implements HandshakingUserAuth {
                 session.writePacket(b);
                 return null;
             } else {
-                return Boolean.valueOf(established);
+                return established;
             }
         }
     }
@@ -240,7 +235,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
      *
      * @return The user name
      */
-
     public String getUserName() throws GSSException {
         return identity;
     }
@@ -248,7 +242,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
     /**
      * Free any system resources used by the module.
      */
-
     public void destroy() {
         if (creds != null) {
             try {
@@ -275,7 +268,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
      * @return The GSS authenticator
      * @throws Exception If no GSS authenticator is defined
      */
-
     private GSSAuthenticator getAuthenticator(ServerSession session) throws Exception {
         GSSAuthenticator ga = session.getServerFactoryManager().getGSSAuthenticator();
 
@@ -292,7 +284,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
      * @param rep The string form
      * @return The Oid
      */
-
     private static Oid createOID(String rep) {
         try {
             return new Oid(rep);
@@ -305,7 +296,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
     /**
      * Factory class.
      */
-
     public static class Factory implements NamedFactory<UserAuth> {
 
         /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index 4582519..75f14d4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -23,6 +23,8 @@ import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.security.KeyPair;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Future;
@@ -30,6 +32,7 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.mina.core.session.IoSession;
+import org.apache.sshd.SshServer;
 import org.apache.sshd.agent.common.AgentForwardSupport;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.*;
@@ -67,9 +70,12 @@ public class ServerSession extends AbstractSession {
     private final AgentForwardSupport agentForward;
     private final X11ForwardSupport x11Forward;
 
-    private HandshakingUserAuth currentAuth;
-
     private List<NamedFactory<UserAuth>> userAuthFactories;
+    private List<List<String>> authMethods;
+    private String authUserName;
+    private String authMethod;
+    private String authService;
+    private HandshakingUserAuth currentAuth;
 
     public ServerSession(FactoryManager server, IoSession ioSession) throws Exception {
         super(server, ioSession);
@@ -183,7 +189,7 @@ public class ServerSession extends AbstractSession {
                         }
                         break;
                     case UserAuth:
-                        if (cmd != SshConstants.Message.SSH_MSG_USERAUTH_REQUEST && (currentAuth == null || !currentAuth.handles(cmd))) {
+                        if (cmd != SshConstants.Message.SSH_MSG_USERAUTH_REQUEST && currentAuth == null) {
                             disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Protocol error: expected packet " + SshConstants.Message.SSH_MSG_USERAUTH_REQUEST + ", got " + cmd);
                             return;
                         }
@@ -358,113 +364,177 @@ public class ServerSession extends AbstractSession {
             buffer.putString("ssh-userauth");
             writePacket(buffer);
             userAuthFactories = new ArrayList<NamedFactory<UserAuth>>(getServerFactoryManager().getUserAuthFactories());
+            // Get authentication methods
+            authMethods = new ArrayList<List<String>>();
+            String mths = getServerFactoryManager().getProperties().get(SshServer.AUTH_METHODS);
+            if (mths == null) {
+                for (NamedFactory<UserAuth> uaf : getServerFactoryManager().getUserAuthFactories()) {
+                    authMethods.add(new ArrayList<String>(Collections.singletonList(uaf.getName())));
+                }
+            } else {
+                for (String mthl : mths.split("\\s")) {
+                    authMethods.add(new ArrayList<String>(Arrays.asList(mthl.split(","))));
+                }
+            }
+            // Verify all required methods are supported
+            for (List<String> l : authMethods) {
+                for (String m : l) {
+                    if (NamedFactory.Utils.get(userAuthFactories, m) == null) {
+                        throw new SshException("Configured method is not supported: " + m);
+                    }
+                }
+            }
             log.debug("Authorized authentication methods: {}", NamedFactory.Utils.getNames(userAuthFactories));
             setState(State.UserAuth);
+
         } else {
-            if (nbAuthRequests++ > maxAuthRequests) {
-                throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too may authentication failures");
-            }
 
-            Boolean authed = null;
-            String username = null;
+            UserAuth auth = this.currentAuth;
+            Boolean authed = Boolean.FALSE;
 
             if (cmd == SshConstants.Message.SSH_MSG_USERAUTH_REQUEST) {
-                username = buffer.getString();
+                if (this.currentAuth != null) {
+                    this.currentAuth.destroy();
+                    this.currentAuth = null;
+                }
 
-                String svcName = buffer.getString();
+                String username = buffer.getString();
+                String service = buffer.getString();
                 String method = buffer.getString();
+                if (this.authUserName == null || this.authService == null) {
+                    this.authUserName = username;
+                    this.authService = service;
+                } else if (!this.authUserName.equals(username) || !this.authService.equals(service)) {
+                    disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR,
+                            "Change of username or service is not allowed (" + this.authUserName + ", " + this.authService + ") -> ("
+                                + username + ", " + service + ")");
+                    return;
+                }
+                this.authMethod = method;
+                if (nbAuthRequests++ > maxAuthRequests) {
+                    disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too may authentication failures");
+                    return;
+                }
 
-                log.debug("Authenticating user '{}' with method '{}'", username, method);
+                log.debug("Authenticating user '{}' with service '{}' and method '{}'", new Object[] { username, service, method });
                 NamedFactory<UserAuth> factory = NamedFactory.Utils.get(userAuthFactories, method);
                 if (factory != null) {
-                    UserAuth auth = factory.create();
+                    auth = factory.create();
                     try {
-                        authed = auth.auth(this, username, buffer);
-                        if (authed == null) {
-                            // authentication is still ongoing
-                            log.debug("Authentication not finished");
-
-                            if (auth instanceof HandshakingUserAuth) {
-                                currentAuth = (HandshakingUserAuth) auth;
-
-                                // GSSAPI needs the user name and service to verify the MIC
-
-                                currentAuth.setServiceName(svcName);
-                            }
-                            return;
-                        } else {
-                            log.debug(authed ? "Authentication succeeded" : "Authentication failed");
-                        }
+                        authed = auth.auth(this, username, service, buffer);
                     } catch (Exception e) {
                         // Continue
-                        authed = false;
                         log.debug("Authentication failed: {}", e.getMessage());
                     }
-
-                } else {
-                    log.debug("Unsupported authentication method '{}'", method);
                 }
-            } else {
+            } else  {
+                if (this.currentAuth == null) {
+                    // This should not happen
+                    throw new IllegalStateException();
+                }
+                buffer.rpos(buffer.rpos() - 1);
                 try {
-                    authed = currentAuth.next(this, cmd, buffer);
-
-                    if (authed == null) {
-                        // authentication is still ongoing
-                        log.debug("Authentication still not finished");
-                        return;
-                    } else if (authed.booleanValue()) {
-                        username = currentAuth.getUserName();
-                    }
+                    authed = currentAuth.next(this, buffer);
                 } catch (Exception e) {
-                    // failed
-                    authed = false;
-                    log.debug("Authentication next failed: {}", e.getMessage());
+                    // Continue
+                    log.debug("Authentication failed: {}", e.getMessage());
                 }
             }
 
-            // No more handshakes now - clean up if necessary
+            if (authed == null) {
+                // authentication is still ongoing
+                log.debug("Authentication not finished");
+                if (auth instanceof HandshakingUserAuth) {
+                    currentAuth = (HandshakingUserAuth) auth;
+                }
+            } else if (authed) {
+                log.debug("Authentication succeeded");
+                if (currentAuth != null) {
+                    username = currentAuth.getUserName();
+                } else {
+                    username = this.authUserName;
+                }
 
-            if (currentAuth != null) {
-                currentAuth.destroy();
-                currentAuth = null;
-            }
+                boolean success = false;
+                for (List<String> l : authMethods) {
+                    if (!l.isEmpty() && l.get(0).equals(authMethod)) {
+                        l.remove(0);
+                        success |= l.isEmpty();
+                    }
+                }
+                if (success) {
+                    if (getFactoryManager().getProperties() != null) {
+                        String maxSessionCountAsString = getFactoryManager().getProperties().get(ServerFactoryManager.MAX_CONCURRENT_SESSIONS);
+                        if (maxSessionCountAsString != null) {
+                            int maxSessionCount = Integer.parseInt(maxSessionCountAsString);
+                            int currentSessionCount = getActiveSessionCountForUser(username);
+                            if (currentSessionCount >= maxSessionCount) {
+                                disconnect(SshConstants.SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE, "Too many concurrent connections");
+                                return;
+                            }
+                        }
+                    }
 
-            if (authed != null && authed) {
+                    String welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
+                    if (welcomeBanner != null) {
+                        buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
+                        buffer.putString(welcomeBanner);
+                        buffer.putString("en");
+                        writePacket(buffer);
+                    }
 
-                if (getFactoryManager().getProperties() != null) {
-                    String maxSessionCountAsString = getFactoryManager().getProperties().get(ServerFactoryManager.MAX_CONCURRENT_SESSIONS);
-                    if (maxSessionCountAsString != null) {
-                        int maxSessionCount = Integer.parseInt(maxSessionCountAsString);
-                        int currentSessionCount = getActiveSessionCountForUser(username);
-                        if (currentSessionCount >= maxSessionCount) {
-                            disconnect(SshConstants.SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE, "Too many concurrent connections");
-                            return;
+                    buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_SUCCESS, 0);
+                    writePacket(buffer);
+                    setState(State.Running);
+                    this.authed = true;
+                    unscheduleAuthTimer();
+                    scheduleIdleTimer();
+                    log.info("Session {}@{} authenticated", getUsername(), getIoSession().getRemoteAddress());
+
+                } else {
+                    buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_FAILURE, 0);
+                    StringBuilder sb = new StringBuilder();
+                    for (List<String> l : authMethods) {
+                        if (!l.isEmpty()) {
+                            if (sb.length() > 0) {
+                                sb.append(",");
+                            }
+                            sb.append(l.get(0));
                         }
                     }
-                }
-
-                String welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
-                if (welcomeBanner != null) {
-                    buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
-                    buffer.putString(welcomeBanner);
-                    buffer.putString("en");
+                    buffer.putString(sb.toString());
+                    buffer.putByte((byte) 1);
                     writePacket(buffer);
                 }
 
-                buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_SUCCESS, 0);
-                writePacket(buffer);
-                setState(State.Running);
-                this.authed = true;
-                this.username = username;
-                unscheduleAuthTimer();
-                scheduleIdleTimer();
-                log.info("Session {}@{} authenticated", getUsername(), getIoSession().getRemoteAddress());
+                if (currentAuth != null) {
+                    currentAuth.destroy();
+                    currentAuth = null;
+                }
             } else {
+                log.debug("Authentication failed");
+
                 buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_FAILURE, 0);
-                NamedFactory.Utils.remove(userAuthFactories, "none"); // 'none' MUST NOT be listed
-                buffer.putString(NamedFactory.Utils.getNames(userAuthFactories));
-                buffer.putByte((byte) 0);
+                StringBuilder sb = new StringBuilder();
+                for (List<String> l : authMethods) {
+                    if (!l.isEmpty()) {
+                        String m = l.get(0);
+                        if (!"none".equals(m)) {
+                            if (sb.length() > 0) {
+                                sb.append(",");
+                            }
+                            sb.append(l.get(0));
+                        }
+                    }
+                }
+                buffer.putString(sb.toString());
+                buffer.putByte((byte) 1);
                 writePacket(buffer);
+
+                if (currentAuth != null) {
+                    currentAuth.destroy();
+                    currentAuth = null;
+                }
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/test/java/org/apache/sshd/AuthenticationTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/AuthenticationTest.java b/sshd-core/src/test/java/org/apache/sshd/AuthenticationTest.java
new file mode 100644
index 0000000..67b5626
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/AuthenticationTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.Logger;
+import com.jcraft.jsch.UserInfo;
+import org.apache.mina.core.filterchain.IoFilterChain;
+import org.apache.mina.core.service.IoProcessor;
+import org.apache.mina.core.service.IoService;
+import org.apache.mina.core.service.TransportMetadata;
+import org.apache.mina.core.session.AbstractIoSession;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
+import org.apache.mina.transport.vmpipe.VmPipeAcceptor;
+import org.apache.mina.transport.vmpipe.VmPipeAddress;
+import org.apache.mina.transport.vmpipe.VmPipeConnector;
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Session;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.server.UserAuth;
+import org.apache.sshd.server.auth.UserAuthPassword;
+import org.apache.sshd.server.auth.UserAuthPublicKey;
+import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.server.session.SessionFactory;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.BogusPublickeyAuthenticator;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.ServerSocket;
+import java.net.SocketAddress;
+import java.security.KeyPair;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class AuthenticationTest {
+
+    private static final String WELCOME = "Welcome to SSHD";
+
+    private SshServer sshd;
+    private int port;
+
+    @Before
+    public void setUp() throws Exception {
+        ServerSocket s = new ServerSocket(0);
+        port = s.getLocalPort();
+        s.close();
+
+        sshd = SshServer.setUpDefaultServer();
+        sshd.setPort(port);
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+        sshd.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());
+        sshd.setUserAuthFactories(Arrays.asList(
+                new UserAuthDummy.Factory(), new UserAuthPassword.Factory(), new UserAuthPublicKey.Factory()
+        ));
+        sshd.getProperties().put(SshServer.WELCOME_BANNER, WELCOME);
+        sshd.getProperties().put(SshServer.AUTH_METHODS, "publickey,password publickey,dummy");
+        sshd.setSessionFactory(new SessionFactory() {
+            @Override
+            protected AbstractSession doCreateSession(IoSession ioSession) throws Exception {
+                return new TestSession(server, ioSession);
+            }
+        });
+        sshd.start();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (sshd != null) {
+            sshd.stop(true);
+            Thread.sleep(50);
+        }
+    }
+
+    @Test
+    public void testChangeUser() throws Exception {
+        SshClient client = SshClient.setUpDefaultClient();
+        client.start();
+        ClientSession s = client.connect("localhost", port).await().getSession();
+        s.waitFor(ClientSession.CLOSED | ClientSession.WAIT_AUTH, 0);
+
+        assertFalse(s.authPassword("user1", "the-password").await().isSuccess());
+        assertFalse(s.authPassword("user2", "the-password").await().isSuccess());
+
+        assertEquals(ClientSession.CLOSED, s.waitFor(ClientSession.CLOSED, 1000));
+    }
+
+    @Test
+    public void testAuth() throws Exception {
+        SshClient client = SshClient.setUpDefaultClient();
+        client.start();
+        ClientSession s = client.connect("localhost", port).await().getSession();
+        s.waitFor(ClientSession.CLOSED | ClientSession.WAIT_AUTH, 0);
+
+        assertFalse(s.authPassword("smx", "smx").await().isSuccess());
+
+        KeyPair pair = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
+        assertFalse(s.authPublicKey("smx", pair).await().isSuccess());
+
+        assertTrue(s.authPassword("smx", "smx").await().isSuccess());
+
+        s.close(true);
+        client.stop();
+    }
+
+    public static class TestSession extends ServerSession {
+        public TestSession(FactoryManager server, IoSession ioSession) throws Exception {
+            super(server, ioSession);
+        }
+        public void setState(State state) {
+            super.setState(state);
+        }
+        public void handleMessage(Buffer buffer) throws Exception {
+            super.handleMessage(buffer);
+        }
+    }
+
+    public static class UserAuthDummy implements UserAuth {
+        public static class Factory implements NamedFactory<UserAuth> {
+            public String getName() {
+                return "dummy";
+            }
+            public UserAuth create() {
+                return new UserAuthDummy();
+            }
+        }
+        public Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception {
+            return Boolean.TRUE;
+        }
+    }
+}


[2/4] git commit: Code formatting

Posted by gn...@apache.org.
Code formatting

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

Branch: refs/heads/master
Commit: 34098dac637f452f8a14ef19cc55511b6d261924
Parents: 5bb8366
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 17 09:03:35 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 17 09:03:35 2013 +0200

----------------------------------------------------------------------
 .../apache/sshd/server/HandshakingUserAuth.java |  96 ++--
 .../sshd/server/auth/gss/CredentialHelper.java  | 162 +++---
 .../sshd/server/auth/gss/GSSAuthenticator.java  | 180 +++---
 .../sshd/server/auth/gss/UserAuthGSS.java       | 550 +++++++++----------
 .../sshd/server/session/ServerSession.java      | 106 ++--
 5 files changed, 539 insertions(+), 555 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
index 485e00f..625f7ba 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
@@ -24,57 +24,55 @@ import org.apache.sshd.server.session.ServerSession;
 
 /**
  * Extension of UserAuth for use with methods which require handshakes, such as gssapi-with-mic.
- * 
+ *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 
 public interface HandshakingUserAuth extends UserAuth {
-  
-  /**
-   * Set the service name from the original request.  This may be required for MIC verification later.
-   * 
-   * @param service The service name
-   */
-  
-  void setServiceName(String service);
-  
-  /**
-   * Check whether a particular message is handled here.
-   * 
-   * @param msg The message
-   * 
-   * @return <code>true</code> if the message is handled
-   */
-  
-  boolean handles(SshConstants.Message msg);
-  
-  /**
-   * Handle another step in the authentication process. 
-   *
-   * @param session the current ssh session
-   * @param msg The message type
-   * @param buffer the request buffer containing parameters specific to this request
-   * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
-   *          is not finished yet
-   * @throws Exception if the authentication fails
-   */
-  
-  Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception;
-  
-  /**
-   * Get a user name which has been derived from the handshaking process, or the intial name if
-   * nothing has been found.
-   * 
-   * @return The user name
-   * 
-   * @throws Exception if the request fails
-   */
-  
-  String getUserName() throws Exception;
-  
-  /**
-   * Free any system resources used by the module.
-   */
-  
-  void destroy();
+
+    /**
+     * Set the service name from the original request.  This may be required for MIC verification later.
+     *
+     * @param service The service name
+     */
+
+    void setServiceName(String service);
+
+    /**
+     * Check whether a particular message is handled here.
+     *
+     * @param msg The message
+     * @return <code>true</code> if the message is handled
+     */
+
+    boolean handles(SshConstants.Message msg);
+
+    /**
+     * Handle another step in the authentication process.
+     *
+     * @param session the current ssh session
+     * @param msg     The message type
+     * @param buffer  the request buffer containing parameters specific to this request
+     * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
+     *         is not finished yet
+     * @throws Exception if the authentication fails
+     */
+
+    Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception;
+
+    /**
+     * Get a user name which has been derived from the handshaking process, or the intial name if
+     * nothing has been found.
+     *
+     * @return The user name
+     * @throws Exception if the request fails
+     */
+
+    String getUserName() throws Exception;
+
+    /**
+     * Free any system resources used by the module.
+     */
+
+    void destroy();
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java
index 91cca9f..37ce5d3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java
@@ -39,94 +39,92 @@ import org.ietf.jgss.GSSManager;
  */
 
 public class CredentialHelper {
-  
-  public static GSSCredential creds(GSSManager mgr, String spn, String keytab) throws LoginException, GSSException {
-    LoginContext lc = new LoginContext("x", null, null, new FixedLoginConfiguration(spn, keytab));         
-    
-    lc.login();
-            
-    try {
-      return (GSSCredential) Subject.doAs(lc.getSubject(), new G(mgr));
-    } catch (PrivilegedActionException e) {
-      throw (GSSException) e.getCause();
-    }
-  }
-  
-  /**
-   * A login configuration which is defined from code.
-   *
-   * @author Richard Evans
-   */
-
-  private static class FixedLoginConfiguration extends Configuration {
-    
-    private AppConfigurationEntry entry;
-    
-    /**
-     * Constructor.
-     */
-    
-    private FixedLoginConfiguration(String spn, String keytab) {
-      Map<String, String> parms = new HashMap<String, String>();
-      
-      parms.put("isInitiator", "false");
-      parms.put("principal",   spn);
-      parms.put("useKeyTab",   "true");
-      parms.put("storeKey",    "true");
-      
-      if (keytab != null) {
-        parms.put("keyTab", keytab);
-      }
-      
-      entry = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, parms);
-    }
-    
-    /**
-     * Get the configuration entries for a name.
-     * 
-     * @param name The name
-     * 
-     * @return The entries, or <code>null</code> if the name is not known
-     */
-    
-    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-      return new AppConfigurationEntry [] { entry };
-    }
 
-    /**
-     * Refresh the configuration.  Nothing to do here.
-     */
-    
-    public void refresh() {    
+    public static GSSCredential creds(GSSManager mgr, String spn, String keytab) throws LoginException, GSSException {
+        LoginContext lc = new LoginContext("x", null, null, new FixedLoginConfiguration(spn, keytab));
+
+        lc.login();
+
+        try {
+            return (GSSCredential) Subject.doAs(lc.getSubject(), new G(mgr));
+        } catch (PrivilegedActionException e) {
+            throw (GSSException) e.getCause();
+        }
     }
-  }
-  
-  /**
-   * Privileged action which runs as the subject to get the credentials.
-   */
-
-  private static final class G implements PrivilegedExceptionAction<GSSCredential> {
-    
-    private GSSManager mgr;
-    
+
     /**
-     * @param mgr The existing GSS manager
+     * A login configuration which is defined from code.
+     *
+     * @author Richard Evans
      */
-    
-    private G(GSSManager mgr) {
-      this.mgr      = mgr;
+
+    private static class FixedLoginConfiguration extends Configuration {
+
+        private AppConfigurationEntry entry;
+
+        /**
+         * Constructor.
+         */
+
+        private FixedLoginConfiguration(String spn, String keytab) {
+            Map<String, String> parms = new HashMap<String, String>();
+
+            parms.put("isInitiator", "false");
+            parms.put("principal", spn);
+            parms.put("useKeyTab", "true");
+            parms.put("storeKey", "true");
+
+            if (keytab != null) {
+                parms.put("keyTab", keytab);
+            }
+
+            entry = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, parms);
+        }
+
+        /**
+         * Get the configuration entries for a name.
+         *
+         * @param name The name
+         * @return The entries, or <code>null</code> if the name is not known
+         */
+
+        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+            return new AppConfigurationEntry[]{entry};
+        }
+
+        /**
+         * Refresh the configuration.  Nothing to do here.
+         */
+
+        public void refresh() {
+        }
     }
-    
+
     /**
-     * Do the action.
-     * 
-     * @return The new credentials
-     * 
-     * @throws GSSException If an error occurred
+     * Privileged action which runs as the subject to get the credentials.
      */
-    
-    public GSSCredential run() throws GSSException {
-      return mgr.createCredential(null, GSSCredential.INDEFINITE_LIFETIME, UserAuthGSS.KRB5_MECH, GSSCredential.ACCEPT_ONLY);      
+
+    private static final class G implements PrivilegedExceptionAction<GSSCredential> {
+
+        private GSSManager mgr;
+
+        /**
+         * @param mgr The existing GSS manager
+         */
+
+        private G(GSSManager mgr) {
+            this.mgr = mgr;
+        }
+
+        /**
+         * Do the action.
+         *
+         * @return The new credentials
+         * @throws GSSException If an error occurred
+         */
+
+        public GSSCredential run() throws GSSException {
+            return mgr.createCredential(null, GSSCredential.INDEFINITE_LIFETIME, UserAuthGSS.KRB5_MECH, GSSCredential.ACCEPT_ONLY);
+        }
     }
-  }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java
index fd988b9..96ef66b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java
@@ -31,101 +31,97 @@ import org.ietf.jgss.GSSManager;
 /**
  * Class providing basic GSS authentication services.  Can be used as-is, but is often extended to provide environment
  * specific implementations.
- * 
+ *
  * @author Richard Evans
  */
 
 public class GSSAuthenticator {
-  
-  // Options:
-  //
-  // Service principal name: if unset, use host/hostname
-  
-  private String servicePrincipalName;
-  
-  // Location of Kerberos key table; if unset use default
-  
-  private String keytabFile;
-
-  /**
-   * Overridable method to get GSS manager suitable for current environment.
-   * 
-   * @return A new manager
-   */
-  
-  public GSSManager getGSSManager() {
-    return GSSManager.getInstance();
-  }
-  
-  /**
-   * Overridable method to get GSS accept credential suitable for the current environment.  The default
-   * implementation uses a Kerberos key table.
-   * 
-   * @param mgr The GSS manager
-   * 
-   * @return The credential; if the result is <code>null</code> gssapi authentication fails immediately
-   * 
-   * @throws UnknownHostException If the local host name could not be determined
-   * @throws LoginException If the subject could not be found
-   * @throws GSSException If the credential could not be obtained
-   */
-  
-  public GSSCredential getGSSCredential(GSSManager mgr) throws UnknownHostException, LoginException, GSSException {
-    
-    String name = servicePrincipalName;
-    
-    if (name == null) {
-      name = "host/" + InetAddress.getLocalHost().getCanonicalHostName();
+
+    // Options:
+    //
+    // Service principal name: if unset, use host/hostname
+
+    private String servicePrincipalName;
+
+    // Location of Kerberos key table; if unset use default
+
+    private String keytabFile;
+
+    /**
+     * Overridable method to get GSS manager suitable for current environment.
+     *
+     * @return A new manager
+     */
+
+    public GSSManager getGSSManager() {
+        return GSSManager.getInstance();
+    }
+
+    /**
+     * Overridable method to get GSS accept credential suitable for the current environment.  The default
+     * implementation uses a Kerberos key table.
+     *
+     * @param mgr The GSS manager
+     * @return The credential; if the result is <code>null</code> gssapi authentication fails immediately
+     * @throws UnknownHostException If the local host name could not be determined
+     * @throws LoginException       If the subject could not be found
+     * @throws GSSException         If the credential could not be obtained
+     */
+
+    public GSSCredential getGSSCredential(GSSManager mgr) throws UnknownHostException, LoginException, GSSException {
+
+        String name = servicePrincipalName;
+
+        if (name == null) {
+            name = "host/" + InetAddress.getLocalHost().getCanonicalHostName();
+        }
+
+        return CredentialHelper.creds(mgr, name, keytabFile);
+    }
+
+    /**
+     * Validate the user name passed in the initial SSH_MSG_USERAUTH_REQUEST message.  This is sort of mandated by RFC 4462, but it
+     * may be more useful to wait for the GSS negotiation to complete.  The default implementation here always succeeds.
+     *
+     * @param session The current session
+     * @param user    The user name from the initial request
+     * @return <code>true</code> if the user is valid, <code>false</code> if invalid
+     */
+
+    public boolean validateInitialUser(ServerSession session, String user) {
+        return true;
+    }
+
+    /**
+     * Validate the source identity obtained from the context after negotiation is complete.
+     * The default implementation here always succeeds.
+     *
+     * @param session  The current session
+     * @param identity The identity from the GSS context
+     * @return <code>true</code> if the identity is valid, <code>false</code> if invalid
+     */
+
+    public boolean validateIdentity(ServerSession session, String identity) {
+        return true;
+    }
+
+    /**
+     * Set the service principal name to be used.  The default is host/hostname.
+     *
+     * @param servicePrincipalName The principal name
+     */
+
+    public void setServicePrincipalName(String servicePrincipalName) {
+        this.servicePrincipalName = servicePrincipalName;
+    }
+
+    /**
+     * Set the location of the Kerberos keytab.  The default is defined by the JRE.
+     *
+     * @param keytabFile The location of the keytab
+     */
+
+    public void setKeytabFile(String keytabFile) {
+        this.keytabFile = keytabFile;
     }
-        
-    return CredentialHelper.creds(mgr, name, keytabFile);  
-  }
-  
-  /**
-   * Validate the user name passed in the initial SSH_MSG_USERAUTH_REQUEST message.  This is sort of mandated by RFC 4462, but it
-   * may be more useful to wait for the GSS negotiation to complete.  The default implementation here always succeeds.
-   * 
-   * @param session The current session
-   * @param user The user name from the initial request
-   * 
-   * @return <code>true</code> if the user is valid, <code>false</code> if invalid
-   */
-  
-  public boolean validateInitialUser(ServerSession session, String user) {
-    return true;
-  }
-  
-  /**
-   * Validate the source identity obtained from the context after negotiation is complete. 
-   * The default implementation here always succeeds.
-   * 
-   * @param session The current session
-   * @param identity The identity from the GSS context
-   * 
-   * @return <code>true</code> if the identity is valid, <code>false</code> if invalid
-   */
-  
-  public boolean validateIdentity(ServerSession session, String identity) {
-    return true;
-  }
-  
-  /**
-   * Set the service principal name to be used.  The default is host/hostname.
-   * 
-   * @param servicePrincipalName The principal name
-   */
-  
-  public void setServicePrincipalName(String servicePrincipalName) {
-    this.servicePrincipalName = servicePrincipalName;
-  }
-  
-  /**
-   * Set the location of the Kerberos keytab.  The default is defined by the JRE.
-   * 
-   * @param keytabFile The location of the keytab
-   */
-  
-  public void setKeytabFile(String keytabFile) {
-    this.keytabFile = keytabFile;
-  }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
index c2518dc..afcca3a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
@@ -36,304 +36,296 @@ import org.slf4j.LoggerFactory;
 /**
  * Prototype user authentication handling gssapi-with-mic.  Implements <code>HandshakingUserAuth</code> because
  * the process involves several steps.
- * 
+ * <p/>
  * Several methods are available for overriding in specific circumstances.
  */
 
 public class UserAuthGSS implements HandshakingUserAuth {
-  
-  // Oids for the Kerberos 5 mechanism and principal 
-  
-  public static final Oid KRB5_MECH         = createOID("1.2.840.113554.1.2.2");
-  public static final Oid KRB5_NT_PRINCIPAL = createOID("1.2.840.113554.1.2.2.1");
-  
-  // Options:
-  //
-  // Service principal name: if unset, use host/hostname
-  
-  private String servicePrincipalName;
-  
-  // Location of Kerberos key table; if unset use default
-  
-  private String keytabFile;
-    
-  // The on-going GSS context.
-  
-  private GSSContext ctxt;
-  
-  // Accept credentials
-  
-  private GSSCredential creds;
-  
-  // Original request data
-  
-  private String user;
-  private String service;
-  
-  // Identity from context
-  
-  private String identity;
-  
-  // Logging
-  
-  private Logger log = LoggerFactory.getLogger(getClass());
-      
-  /**
-   * Handle the first authentication step.
-   * 
-   * @param sess The server session
-   * @param user The user name from the request
-   * @param buff The request buffer
-   * 
-   * @return True or false if the authentication succeeded, or <code>null</code> to continue further
-   * 
-   * @throws Exception If something went wrong
-   */
-  
-  public Boolean auth(ServerSession sess, String user, Buffer buff) throws Exception {
-    GSSAuthenticator auth = getAuthenticator(sess);
-    
-    this.user = user;
-
-    // Get mechanism count from buffer and look for Kerberos 5.
-    
-    int num = buff.getInt();
-    
-    for (int i = 0; i < num; i++) {
-      Oid oid = new Oid(buff.getBytes());
-      
-      if (oid.equals(KRB5_MECH)) {
-        log.debug("UserAuthGSS: found Kerberos 5");
-        
-        // Validate initial user before proceeding
-        
-        if (!auth.validateInitialUser(sess, user)) {
-          return Boolean.FALSE;
-        }
 
-        GSSManager    mgr   = auth.getGSSManager();
-        GSSCredential creds = auth.getGSSCredential(mgr);
-        
-        if (creds == null) {
-          return Boolean.FALSE;
+    // Oids for the Kerberos 5 mechanism and principal
+
+    public static final Oid KRB5_MECH = createOID("1.2.840.113554.1.2.2");
+    public static final Oid KRB5_NT_PRINCIPAL = createOID("1.2.840.113554.1.2.2.1");
+
+    // Options:
+    //
+    // Service principal name: if unset, use host/hostname
+
+    private String servicePrincipalName;
+
+    // Location of Kerberos key table; if unset use default
+
+    private String keytabFile;
+
+    // The on-going GSS context.
+
+    private GSSContext ctxt;
+
+    // Accept credentials
+
+    private GSSCredential creds;
+
+    // Original request data
+
+    private String user;
+    private String service;
+
+    // Identity from context
+
+    private String identity;
+
+    // Logging
+
+    private Logger log = LoggerFactory.getLogger(getClass());
+
+    /**
+     * Handle the first authentication step.
+     *
+     * @param sess The server session
+     * @param user The user name from the request
+     * @param buff The request buffer
+     * @return True or false if the authentication succeeded, or <code>null</code> to continue further
+     * @throws Exception If something went wrong
+     */
+
+    public Boolean auth(ServerSession sess, String user, Buffer buff) throws Exception {
+        GSSAuthenticator auth = getAuthenticator(sess);
+
+        this.user = user;
+
+        // Get mechanism count from buffer and look for Kerberos 5.
+
+        int num = buff.getInt();
+
+        for (int i = 0; i < num; i++) {
+            Oid oid = new Oid(buff.getBytes());
+
+            if (oid.equals(KRB5_MECH)) {
+                log.debug("UserAuthGSS: found Kerberos 5");
+
+                // Validate initial user before proceeding
+
+                if (!auth.validateInitialUser(sess, user)) {
+                    return Boolean.FALSE;
+                }
+
+                GSSManager mgr = auth.getGSSManager();
+                GSSCredential creds = auth.getGSSCredential(mgr);
+
+                if (creds == null) {
+                    return Boolean.FALSE;
+                }
+
+                ctxt = mgr.createContext(creds);
+
+                // Send the matching mechanism back to the client
+
+                Buffer b = sess.createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_INFO_REQUEST, 0);
+                byte[] out = oid.getDER();
+
+                b.putBytes(out);
+                sess.writePacket(b);
+
+                return null;
+            }
         }
 
-        ctxt = mgr.createContext(creds);
-        
-        // Send the matching mechanism back to the client
+        // No matching mechanism found
+
+        return Boolean.FALSE;
+    }
 
-        Buffer  b   = sess.createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_INFO_REQUEST, 0);
-        byte [] out = oid.getDER();
+    /**
+     * Set the service name from the original request.  This may be required for MIC verification later.
+     *
+     * @param service The service name
+     */
 
-        b.putBytes(out);
-        sess.writePacket(b);
-        
-        return null;
-      }
+    public void setServiceName(String service) {
+        this.service = service;
     }
-          
-    // No matching mechanism found
-    
-    return Boolean.FALSE;
-  }
-  
-  /**
-   * Set the service name from the original request.  This may be required for MIC verification later.
-   * 
-   * @param service The service name
-   */
-  
-  public void setServiceName(String service) {
-    this.service = service;
-  }
-  
-  /**
-   * Check whether a particular message is handled here.
-   * 
-   * @param msg The message
-   * 
-   * @return <code>true</code> if the message is handled
-   */
-  
-  public boolean handles(SshConstants.Message msg) {
-    return msg == SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE || msg == SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC && ctxt.isEstablished();
-  }
-  
-  /**
-   * Handle another step in the authentication process. 
-   *
-   * @param session the current ssh session
-   * @param buffer the request buffer containing parameters specific to this request
-   * 
-   * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
-   * is not finished yet
-   * 
-   * @throws Exception if the authentication fails
-   */
-  
-  public Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception {
-    GSSAuthenticator auth = getAuthenticator(session);
-
-    log.debug("In krb5.next: msg = " + msg);
-
-    // If the context is established, this must be a MIC message
-
-    if (ctxt.isEstablished()) {
-      
-      if (msg != SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC) {
-        return Boolean.FALSE;
-      }
-      
-      // Make the MIC message so the token can be verified
-
-      Buffer msgbuf = new Buffer();
-      
-      msgbuf.putString(session.getSessionId());
-      msgbuf.putByte(SshConstants.Message.SSH_MSG_USERAUTH_REQUEST.toByte());
-      msgbuf.putString(user.getBytes("UTF-8"));
-      msgbuf.putString(service);
-      msgbuf.putString("gssapi-with-mic");
-      
-      byte [] msgbytes = msgbuf.getCompactData();
-      byte [] inmic    = buffer.getBytes();
-
-      try {
-        ctxt.verifyMIC(inmic, 0, inmic.length, msgbytes, 0, msgbytes.length, new MessageProp(false));
-        log.debug("MIC verified");
-        return Boolean.TRUE;
-      } catch (GSSException e) {
-        log.info("GSS verification error: {}", e.toString());
-        return Boolean.FALSE;
-      }
-      
-    } else {
-      
-      // Not established - new token to process
-
-      byte [] tok         = buffer.getBytes();
-      byte [] out         = ctxt.acceptSecContext(tok, 0, tok.length);
-      boolean established = ctxt.isEstablished();
-      
-      // Validate identity if context is now established
-      
-      if (established && identity == null) {
-        identity = ctxt.getSrcName().toString();
-        log.info("GSS identity is {}", identity);
-        
-        if (!auth.validateIdentity(session, identity)) {
-          return Boolean.FALSE;
-        }
-      }
-      
-      // Send return token if necessary
-      
-      if (out != null && out.length > 0) {
-        Buffer b = session.createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE, 0);
-        
-        b.putBytes(out);
-        session.writePacket(b);
-        return null;
-      } else {
-        return Boolean.valueOf(established);
-      }
+
+    /**
+     * Check whether a particular message is handled here.
+     *
+     * @param msg The message
+     * @return <code>true</code> if the message is handled
+     */
+
+    public boolean handles(SshConstants.Message msg) {
+        return msg == SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE || msg == SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC && ctxt.isEstablished();
     }
-  }
-  
-  /**
-   * Get a user name which has been derived from the handshaking process, or the initial name if
-   * nothing has been found.
-   * 
-   * @return The user name
-   */
-  
-  public String getUserName() throws GSSException {
-    return identity;
-  }
-  
-  /**
-   * Free any system resources used by the module.
-   */
-  
-  public void destroy() {
-    if (creds != null) {
-      try {
-        creds.dispose();
-      } catch (GSSException e) {
-        // ignore
-      }
-    
-      if (ctxt != null) {
-        
-        try {
-          ctxt.dispose();
-        } catch (GSSException e) {
-          // ignore
+
+    /**
+     * Handle another step in the authentication process.
+     *
+     * @param session the current ssh session
+     * @param buffer  the request buffer containing parameters specific to this request
+     * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
+     *         is not finished yet
+     * @throws Exception if the authentication fails
+     */
+
+    public Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception {
+        GSSAuthenticator auth = getAuthenticator(session);
+
+        log.debug("In krb5.next: msg = " + msg);
+
+        // If the context is established, this must be a MIC message
+
+        if (ctxt.isEstablished()) {
+
+            if (msg != SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC) {
+                return Boolean.FALSE;
+            }
+
+            // Make the MIC message so the token can be verified
+
+            Buffer msgbuf = new Buffer();
+
+            msgbuf.putString(session.getSessionId());
+            msgbuf.putByte(SshConstants.Message.SSH_MSG_USERAUTH_REQUEST.toByte());
+            msgbuf.putString(user.getBytes("UTF-8"));
+            msgbuf.putString(service);
+            msgbuf.putString("gssapi-with-mic");
+
+            byte[] msgbytes = msgbuf.getCompactData();
+            byte[] inmic = buffer.getBytes();
+
+            try {
+                ctxt.verifyMIC(inmic, 0, inmic.length, msgbytes, 0, msgbytes.length, new MessageProp(false));
+                log.debug("MIC verified");
+                return Boolean.TRUE;
+            } catch (GSSException e) {
+                log.info("GSS verification error: {}", e.toString());
+                return Boolean.FALSE;
+            }
+
+        } else {
+
+            // Not established - new token to process
+
+            byte[] tok = buffer.getBytes();
+            byte[] out = ctxt.acceptSecContext(tok, 0, tok.length);
+            boolean established = ctxt.isEstablished();
+
+            // Validate identity if context is now established
+
+            if (established && identity == null) {
+                identity = ctxt.getSrcName().toString();
+                log.info("GSS identity is {}", identity);
+
+                if (!auth.validateIdentity(session, identity)) {
+                    return Boolean.FALSE;
+                }
+            }
+
+            // Send return token if necessary
+
+            if (out != null && out.length > 0) {
+                Buffer b = session.createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE, 0);
+
+                b.putBytes(out);
+                session.writePacket(b);
+                return null;
+            } else {
+                return Boolean.valueOf(established);
+            }
         }
-      }
     }
-  }
-  
-  /**
-   * Utility to get the configured GSS authenticator for the server, throwing an exception if none is available.
-   * 
-   * @param session The current session
-   * 
-   * @return The GSS authenticator
-   * 
-   * @throws Exception If no GSS authenticator is defined
-   */
-  
-  private GSSAuthenticator getAuthenticator(ServerSession session) throws Exception {
-    GSSAuthenticator ga = session.getServerFactoryManager().getGSSAuthenticator();
-    
-    if (ga == null) {
-      throw new Exception("No GSSAuthenticator configured");
-    } else {
-      return ga;
+
+    /**
+     * Get a user name which has been derived from the handshaking process, or the initial name if
+     * nothing has been found.
+     *
+     * @return The user name
+     */
+
+    public String getUserName() throws GSSException {
+        return identity;
+    }
+
+    /**
+     * Free any system resources used by the module.
+     */
+
+    public void destroy() {
+        if (creds != null) {
+            try {
+                creds.dispose();
+            } catch (GSSException e) {
+                // ignore
+            }
+
+            if (ctxt != null) {
+
+                try {
+                    ctxt.dispose();
+                } catch (GSSException e) {
+                    // ignore
+                }
+            }
+        }
     }
-  }
-  
-  /**
-   * Utility to construct an Oid from a string, ignoring the annoying exception.
-   * 
-   * @param rep The string form
-   * 
-   * @return The Oid
-   */
-  
-  private static Oid createOID(String rep) {
-    try {
-      return new Oid(rep);
-    } catch (GSSException e) {
-      // won't happen
-      return null;
+
+    /**
+     * Utility to get the configured GSS authenticator for the server, throwing an exception if none is available.
+     *
+     * @param session The current session
+     * @return The GSS authenticator
+     * @throws Exception If no GSS authenticator is defined
+     */
+
+    private GSSAuthenticator getAuthenticator(ServerSession session) throws Exception {
+        GSSAuthenticator ga = session.getServerFactoryManager().getGSSAuthenticator();
+
+        if (ga == null) {
+            throw new Exception("No GSSAuthenticator configured");
+        } else {
+            return ga;
+        }
     }
-  }
-  
-  /**
-   * Factory class.
-   */
-
-  public static class Factory implements NamedFactory<UserAuth> {
-    
+
     /**
-     * Get the name of the authentication method.
-     * 
-     * @return Tge name, always 'gssapi-with-mic' here.
+     * Utility to construct an Oid from a string, ignoring the annoying exception.
+     *
+     * @param rep The string form
+     * @return The Oid
      */
-    
-    public String getName() {
-      return "gssapi-with-mic";
+
+    private static Oid createOID(String rep) {
+        try {
+            return new Oid(rep);
+        } catch (GSSException e) {
+            // won't happen
+            return null;
+        }
     }
-  
+
     /**
-     * Create a new authenticator instance.
-     * 
-     * @return The instance
+     * Factory class.
      */
-    
-    public UserAuth create() {
-      return new UserAuthGSS();
+
+    public static class Factory implements NamedFactory<UserAuth> {
+
+        /**
+         * Get the name of the authentication method.
+         *
+         * @return Tge name, always 'gssapi-with-mic' here.
+         */
+
+        public String getName() {
+            return "gssapi-with-mic";
+        }
+
+        /**
+         * Create a new authenticator instance.
+         *
+         * @return The instance
+         */
+
+        public UserAuth create() {
+            return new UserAuthGSS();
+        }
     }
-  }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index f095ed7..d87fdd4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -364,69 +364,69 @@ public class ServerSession extends AbstractSession {
             if (nbAuthRequests++ > maxAuthRequests) {
                 throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too may authentication failures");
             }
-            
-            Boolean authed   = null;
-            String  username = null;
+
+            Boolean authed = null;
+            String username = null;
 
             if (cmd == SshConstants.Message.SSH_MSG_USERAUTH_REQUEST) {
-              username = buffer.getString();
-              
-              String svcName = buffer.getString();
-              String method = buffer.getString();
-              
-              log.debug("Authenticating user '{}' with method '{}'", username, method);
-              NamedFactory<UserAuth> factory = NamedFactory.Utils.get(userAuthFactories, method);
-              if (factory != null) {
-                UserAuth auth = factory.create();
-                try {
-                  authed = auth.auth(this, username, buffer);
-                  if (authed == null) {
-                    // authentication is still ongoing
-                    log.debug("Authentication not finished");
-                    
-                    if (auth instanceof HandshakingUserAuth) {
-                      currentAuth = (HandshakingUserAuth) auth;
-                      
-                      // GSSAPI needs the user name and service to verify the MIC
-                      
-                      currentAuth.setServiceName(svcName);
+                username = buffer.getString();
+
+                String svcName = buffer.getString();
+                String method = buffer.getString();
+
+                log.debug("Authenticating user '{}' with method '{}'", username, method);
+                NamedFactory<UserAuth> factory = NamedFactory.Utils.get(userAuthFactories, method);
+                if (factory != null) {
+                    UserAuth auth = factory.create();
+                    try {
+                        authed = auth.auth(this, username, buffer);
+                        if (authed == null) {
+                            // authentication is still ongoing
+                            log.debug("Authentication not finished");
+
+                            if (auth instanceof HandshakingUserAuth) {
+                                currentAuth = (HandshakingUserAuth) auth;
+
+                                // GSSAPI needs the user name and service to verify the MIC
+
+                                currentAuth.setServiceName(svcName);
+                            }
+                            return;
+                        } else {
+                            log.debug(authed ? "Authentication succeeded" : "Authentication failed");
+                        }
+                    } catch (Exception e) {
+                        // Continue
+                        authed = false;
+                        log.debug("Authentication failed: {}", e.getMessage());
                     }
-                    return;
-                  } else {
-                    log.debug(authed ? "Authentication succeeded" : "Authentication failed");
-                  }
-                } catch (Exception e) {
-                  // Continue
-                  authed = false;
-                  log.debug("Authentication failed: {}", e.getMessage());
+
+                } else {
+                    log.debug("Unsupported authentication method '{}'", method);
                 }
-                
-              } else {
-                log.debug("Unsupported authentication method '{}'", method);
-              }
             } else {
-              try {
-                authed = currentAuth.next(this, cmd, buffer);
-                
-                if (authed == null) {
-                  // authentication is still ongoing
-                  log.debug("Authentication still not finished");
-                  return;
-                } else if (authed.booleanValue()) {
-                  username = currentAuth.getUserName();
+                try {
+                    authed = currentAuth.next(this, cmd, buffer);
+
+                    if (authed == null) {
+                        // authentication is still ongoing
+                        log.debug("Authentication still not finished");
+                        return;
+                    } else if (authed.booleanValue()) {
+                        username = currentAuth.getUserName();
+                    }
+                } catch (Exception e) {
+                    // failed
+                    authed = false;
+                    log.debug("Authentication next failed: {}", e.getMessage());
                 }
-              } catch (Exception e) {
-                // failed
-                authed = false;
-                log.debug("Authentication next failed: {}", e.getMessage());
-              }
             }
 
             // No more handshakes now - clean up if necessary
-            
+
             if (currentAuth != null) {
-              currentAuth.destroy();
-              currentAuth = null;
+                currentAuth.destroy();
+                currentAuth = null;
             }
 
             if (authed != null && authed) {


Re: [3/4] git commit: [SSHD-195] Client side welcome banner support

Posted by sebb <se...@gmail.com>.
On 17 July 2013 15:32,  <gn...@apache.org> wrote:
> [SSHD-195] Client side welcome banner support
>
> Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
> Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/1937ee8e
> Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/1937ee8e
> Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/1937ee8e
>
> Branch: refs/heads/master
> Commit: 1937ee8ebbebb2886ba5bcab0705a80e57a8f286
> Parents: 34098da
> Author: Guillaume Nodet <gn...@apache.org>
> Authored: Wed Jul 17 10:28:59 2013 +0200
> Committer: Guillaume Nodet <gn...@apache.org>
> Committed: Wed Jul 17 10:28:59 2013 +0200
>
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
> index d87fdd4..4582519 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
> @@ -447,7 +447,7 @@ public class ServerSession extends AbstractSession {
>                  if (welcomeBanner != null) {
>                      buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
>                      buffer.putString(welcomeBanner);
> -                    buffer.putString("\n");
> +                    buffer.putString("en");

Huh?

[3/4] git commit: [SSHD-195] Client side welcome banner support

Posted by gn...@apache.org.
[SSHD-195] Client side welcome banner support

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

Branch: refs/heads/master
Commit: 1937ee8ebbebb2886ba5bcab0705a80e57a8f286
Parents: 34098da
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 17 10:28:59 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 17 10:28:59 2013 +0200

----------------------------------------------------------------------
 .../main/java/org/apache/sshd/SshClient.java    | 10 +++
 .../sshd/client/ClientFactoryManager.java       |  7 ++
 .../org/apache/sshd/client/UserInteraction.java | 35 +++++++++
 .../sshd/client/session/ClientSessionImpl.java  | 43 +++++++----
 .../sshd/server/session/ServerSession.java      |  2 +-
 .../java/org/apache/sshd/WelcomeBannerTest.java | 79 ++++++++++++++++++++
 6 files changed, 159 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
index c0b8167..336145f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
@@ -40,6 +40,7 @@ import org.apache.mina.transport.socket.nio.NioSocketConnector;
 import org.apache.sshd.client.ClientFactoryManager;
 import org.apache.sshd.client.ServerKeyVerifier;
 import org.apache.sshd.client.SessionFactory;
+import org.apache.sshd.client.UserInteraction;
 import org.apache.sshd.client.channel.ChannelShell;
 import org.apache.sshd.client.future.ConnectFuture;
 import org.apache.sshd.client.future.DefaultConnectFuture;
@@ -134,6 +135,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
 
     protected IoConnector connector;
     protected SessionFactory sessionFactory;
+    protected UserInteraction userInteraction;
 
     private ServerKeyVerifier serverKeyVerifier;
 
@@ -156,6 +158,14 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
         this.serverKeyVerifier = serverKeyVerifier;
     }
 
+    public UserInteraction getUserInteraction() {
+        return userInteraction;
+    }
+
+    public void setUserInteraction(UserInteraction userInteraction) {
+        this.userInteraction = userInteraction;
+    }
+
     protected void checkConfig() {
         if (getKeyExchangeFactories() == null) {
             throw new IllegalArgumentException("KeyExchangeFactories not set");

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
index 3812b8c..f83d618 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
@@ -54,4 +54,11 @@ public interface ClientFactoryManager extends FactoryManager {
      * @return A <code>TcpipForwarderFactory</code>
      */
     TcpipForwarderFactory getTcpipForwarderFactory();
+
+    /**
+     * Retrieve the UserInteraction object to communicate with the user.
+     *
+     * @return A <code>UserInteraction</code> or <code>null</code>
+     */
+    UserInteraction getUserInteraction();
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/client/UserInteraction.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/UserInteraction.java b/sshd-core/src/main/java/org/apache/sshd/client/UserInteraction.java
new file mode 100644
index 0000000..72dbca5
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/UserInteraction.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ * 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>
+ */
+public interface UserInteraction {
+
+    /**
+     * Displays the welcome banner to the user.
+     *
+     * @param banner the welcome banner
+     */
+    void welcome(String banner);
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index 35748ef..37f7175 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -30,6 +30,7 @@ import org.apache.sshd.ClientChannel;
 import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.ClientFactoryManager;
 import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.client.UserInteraction;
 import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.client.UserAuth;
 import org.apache.sshd.client.auth.UserAuthAgent;
@@ -345,22 +346,32 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
                         if (userAuth == null) {
                             throw new IllegalStateException("State is userAuth, but no user auth pending!!!");
                         }
-                        buffer.rpos(buffer.rpos() - 1);
-                        switch (userAuth.next(buffer)) {
-                             case Success:
-                                 authFuture.setAuthed(true);
-                                 username = userAuth.getUsername();
-                                 authed = true;
-                                 setState(State.Running);
-                                 startHeartBeat();
-                                 break;
-                             case Failure:
-                                 authFuture.setAuthed(false);
-                                 userAuth = null;
-                                 setState(State.WaitForAuth);
-                                 break;
-                             case Continued:
-                                 break;
+                        if (cmd == SshConstants.Message.SSH_MSG_USERAUTH_BANNER) {
+                            String welcome = buffer.getString();
+                            String lang = buffer.getString();
+                            log.debug("Welcome banner: " + welcome);
+                            UserInteraction ui = getClientFactoryManager().getUserInteraction();
+                            if (ui != null) {
+                                ui.welcome(welcome);
+                            }
+                        } else {
+                            buffer.rpos(buffer.rpos() - 1);
+                            switch (userAuth.next(buffer)) {
+                                 case Success:
+                                     authFuture.setAuthed(true);
+                                     username = userAuth.getUsername();
+                                     authed = true;
+                                     setState(State.Running);
+                                     startHeartBeat();
+                                     break;
+                                 case Failure:
+                                     authFuture.setAuthed(false);
+                                     userAuth = null;
+                                     setState(State.WaitForAuth);
+                                     break;
+                                 case Continued:
+                                     break;
+                            }
                         }
                         break;
                     case Running:

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index d87fdd4..4582519 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -447,7 +447,7 @@ public class ServerSession extends AbstractSession {
                 if (welcomeBanner != null) {
                     buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
                     buffer.putString(welcomeBanner);
-                    buffer.putString("\n");
+                    buffer.putString("en");
                     writePacket(buffer);
                 }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/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
new file mode 100644
index 0000000..bb5a222
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.BogusPublickeyAuthenticator;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.ServerSocket;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static junit.framework.Assert.assertEquals;
+
+public class WelcomeBannerTest {
+
+    private static final String WELCOME = "Welcome to SSHD";
+
+    private SshServer sshd;
+    private int port;
+
+    @Before
+    public void setUp() throws Exception {
+        ServerSocket s = new ServerSocket(0);
+        port = s.getLocalPort();
+        s.close();
+
+        sshd = SshServer.setUpDefaultServer();
+        sshd.setPort(port);
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+        sshd.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());
+        sshd.getProperties().put(SshServer.WELCOME_BANNER, WELCOME);
+        sshd.start();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (sshd != null) {
+            sshd.stop(true);
+            Thread.sleep(50);
+        }
+    }
+
+    @Test
+    public void testBanner() throws Exception {
+        final AtomicReference<String> welcome = new AtomicReference<String>();
+        SshClient client = SshClient.setUpDefaultClient();
+        client.setUserInteraction(new UserInteraction() {
+            public void welcome(String banner) {
+                welcome.set(banner);
+            }
+        });
+        client.start();
+        ClientSession session = client.connect("localhost", port).await().getSession();
+        session.authPassword("smx", "smx").await().isSuccess();
+        assertEquals(WELCOME, welcome.get());
+        session.close(true);
+    }
+}