You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/12/14 10:14:08 UTC

[4/4] mina-sshd git commit: [SSHD-612] Cannot attempt new authentication on same session if current one fails

[SSHD-612] Cannot attempt new authentication on same session if current one fails


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

Branch: refs/heads/master
Commit: a26ef1549dde1df7e5cee53b46961c1a49ba74b0
Parents: fa724c2
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Mon Dec 14 11:13:51 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Mon Dec 14 11:13:51 2015 +0200

----------------------------------------------------------------------
 .../client/session/ClientUserAuthService.java   | 53 +++++++++++++++-----
 1 file changed, 41 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a26ef154/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
index ae5bf7a..23c1b4b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
@@ -19,9 +19,11 @@
 package org.apache.sshd.client.session;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.client.ClientAuthenticationManager;
 import org.apache.sshd.client.auth.UserAuth;
@@ -51,17 +53,15 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
      * The AuthFuture that is being used by the current auth request.  This encodes the state.
      * isSuccess -> authenticated, else if isDone -> server waiting for user auth, else authenticating.
      */
-    private final AuthFuture authFuture;
+    private final AtomicReference<AuthFuture> authFutureHolder = new AtomicReference<>();
 
     private final ClientSessionImpl clientSession;
+    private final List<String> clientMethods;
+    private final List<NamedFactory<UserAuth>> authFactories;
 
     private String service;
-
-    private List<NamedFactory<UserAuth>> authFactories;
-    private List<String> clientMethods;
     private List<String> serverMethods;
     private UserAuth userAuth;
-
     private int currentMethod;
 
     public ClientUserAuthService(Session s) {
@@ -69,8 +69,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
             throw new IllegalStateException("Client side service used on server side");
         }
         clientSession = (ClientSessionImpl) s;
-        authFuture = new DefaultAuthFuture(clientSession.getLock());
-        authFactories = clientSession.getUserAuthFactories();
+        authFactories = ValidateUtils.checkNotNullAndNotEmpty(
+                clientSession.getUserAuthFactories(), "No user auth factories for %s", s);
         clientMethods = new ArrayList<>();
 
         String prefs = PropertyResolverUtils.getString(s, ClientAuthenticationManager.PREFERRED_AUTHS);
@@ -116,14 +116,38 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
     }
 
     public AuthFuture auth(String service) throws IOException {
-        this.service = ValidateUtils.checkNotNullAndNotEmpty(service, "No service");
+        this.service = ValidateUtils.checkNotNullAndNotEmpty(service, "No service name");
 
         ClientSession session = getClientSession();
-        String username = session.getUsername();
+        // check if any previous future in use
+        AuthFuture authFuture = new DefaultAuthFuture(clientSession.getLock());
+        AuthFuture currentFuture = authFutureHolder.getAndSet(authFuture);
+        if (currentFuture != null) {
+            if (currentFuture.isDone()) {
+                if (log.isDebugEnabled()) {
+                    log.debug("auth({})[{}] request new authentication", session, service);
+                }
+            } else {
+                currentFuture.setException(new InterruptedIOException("New authentication started before previous completed"));
+            }
+        }
+
+        // start from scratch
+        serverMethods = null;
+        currentMethod = 0;
+        if (userAuth != null) {
+            try {
+                userAuth.destroy();
+            } finally {
+                userAuth = null;
+            }
+        }
+
         if (log.isDebugEnabled()) {
             log.debug("auth({})[{}] send SSH_MSG_USERAUTH_REQUEST for 'none'", session, service);
         }
 
+        String username = session.getUsername();
         Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, username.length() + service.length() + Integer.SIZE);
         buffer.putString(username);
         buffer.putString(service);
@@ -136,9 +160,10 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
     @Override
     public void process(int cmd, Buffer buffer) throws Exception {
         ClientSession session = getClientSession();
-        if (this.authFuture.isSuccess()) {
+        AuthFuture authFuture = ValidateUtils.checkNotNull(authFutureHolder.get(), "No current future");
+        if (authFuture.isSuccess()) {
             throw new IllegalStateException("UserAuth message delivered to authenticated client");
-        } else if (this.authFuture.isDone()) {
+        } else if (authFuture.isDone()) {
             if (log.isDebugEnabled()) {
                 log.debug("process({}) Ignoring random message - cmd={}",
                           session, SshConstants.getCommandMessageName(cmd));
@@ -184,6 +209,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
             }
             session.setAuthenticated();
             ((ClientSessionImpl) session).switchToNextService();
+
+            AuthFuture authFuture = ValidateUtils.checkNotNull(authFutureHolder.get(), "No current future");
             // Will wake up anyone sitting in waitFor
             authFuture.setAuthed(true);
             return;
@@ -270,6 +297,7 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
                 }
 
                 // also wake up anyone sitting in waitFor
+                AuthFuture authFuture = ValidateUtils.checkNotNull(authFutureHolder.get(), "No current future");
                 authFuture.setException(new SshException(SshConstants.SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, "No more authentication methods available"));
                 return;
             }
@@ -289,7 +317,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
 
     @Override
     protected void preClose() {
-        if (!authFuture.isDone()) {
+        AuthFuture authFuture = authFutureHolder.get();
+        if ((authFuture != null) && (!authFuture.isDone())) {
             authFuture.setException(new SshException("Session is closed"));
         }