[prev in list] [next in list] [prev in thread] [next in thread]
List: mina-commits
Subject: [1/3] [SSHD-235][SSHD-287] Refactor client side authentication API, support partial authentication
From: gnodet () apache ! org
Date: 2014-01-31 10:52:10
Message-ID: dcda6238e01d4dbd9d025edd5d487665 () git ! apache ! org
[Download RAW message or body]
Updated Branches:
refs/heads/master d5b96d9fe -> 8f7dff123
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthServiceOld.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthServiceOld.java \
b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthServiceOld.java
new file mode 100644
index 0000000..389fe39
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthServiceOld.java
@@ -0,0 +1,189 @@
+/*
+ * 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.session;
+
+import java.io.IOException;
+
+import org.apache.sshd.client.auth.deprecated.UserAuth;
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.future.DefaultAuthFuture;
+import org.apache.sshd.common.Service;
+import org.apache.sshd.common.Session;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.DefaultCloseFuture;
+import org.apache.sshd.common.util.Buffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Client side <code>ssh-auth</code> service.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class ClientUserAuthServiceOld implements Service {
+
+ /** Our logger */
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * When !authFuture.isDone() the current authentication
+ */
+ private UserAuth userAuth;
+
+ /**
+ * 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 volatile AuthFuture authFuture;
+
+ protected final ClientSessionImpl session;
+ protected final Object lock;
+
+ public ClientUserAuthServiceOld(Session s) {
+ if (!(s instanceof ClientSessionImpl)) {
+ throw new IllegalStateException("Client side service used on server \
side"); + }
+ session = (ClientSessionImpl) s;
+ lock = session.getLock();
+ // Maintain the current auth status in the authFuture.
+ authFuture = new DefaultAuthFuture(lock);
+ }
+
+ public ClientSessionImpl getSession() {
+ return session;
+ }
+
+ public void start() {
+ synchronized (lock) {
+ log.debug("accepted");
+ // kick start the authentication process by failing the pending auth.
+ this.authFuture.setAuthed(false);
+ }
+ }
+
+ public void process(byte cmd, Buffer buffer) throws Exception {
+ if (this.authFuture.isSuccess()) {
+ throw new IllegalStateException("UserAuth message delivered to \
authenticated client"); + } else if (this.authFuture.isDone()) {
+ log.debug("Ignoring random message");
+ // ignore for now; TODO: random packets
+ } else if (cmd == SshConstants.SSH_MSG_USERAUTH_BANNER) {
+ String welcome = buffer.getString();
+ String lang = buffer.getString();
+ log.debug("Welcome banner: {}", welcome);
+ UserInteraction ui = session.getFactoryManager().getUserInteraction();
+ if (ui != null) {
+ ui.welcome(welcome);
+ }
+ } else {
+ buffer.rpos(buffer.rpos() - 1);
+ processUserAuth(buffer);
+ }
+ }
+
+ /**
+ * return true if/when ready for auth; false if never ready.
+ * @return server is ready and waiting for auth
+ */
+ private boolean readyForAuth(UserAuth userAuth) {
+ // isDone indicates that the last auth finished and a new one can commence.
+ while (!this.authFuture.isDone()) {
+ log.debug("waiting to send authentication");
+ try {
+ this.authFuture.await();
+ } catch (InterruptedException e) {
+ log.debug("Unexpected interrupt", e);
+ throw new RuntimeException(e);
+ }
+ }
+ if (this.authFuture.isSuccess()) {
+ log.debug("already authenticated");
+ throw new IllegalStateException("Already authenticated");
+ }
+ if (this.authFuture.getException() != null) {
+ log.debug("probably closed", this.authFuture.getException());
+ return false;
+ }
+ if (!this.authFuture.isFailure()) {
+ log.debug("unexpected state");
+ throw new IllegalStateException("Unexpected authentication state");
+ }
+ if (this.userAuth != null) {
+ log.debug("authentication already in progress");
+ throw new IllegalStateException("Authentication already in progress?");
+ }
+ // Set up the next round of authentication. Each round gets a new lock.
+ this.userAuth = userAuth;
+ // The new future !isDone() - i.e., in progress blocking out other waits.
+ this.authFuture = new DefaultAuthFuture(lock);
+ log.debug("ready to try authentication with new lock");
+ return true;
+ }
+
+ /**
+ * execute one step in user authentication.
+ * @param buffer
+ * @throws java.io.IOException
+ */
+ private void processUserAuth(Buffer buffer) throws IOException {
+ log.debug("processing {}", userAuth);
+ switch (userAuth.next(buffer)) {
+ case Success:
+ log.debug("succeeded with {}", userAuth);
+ session.setAuthenticated();
+ session.switchToNextService();
+ // Will wake up anyone sitting in waitFor
+ authFuture.setAuthed(true);
+ break;
+ case Failure:
+ log.debug("failed with {}", userAuth);
+ this.userAuth = null;
+ // Will wake up anyone sitting in waitFor
+ this.authFuture.setAuthed(false);
+ break;
+ case Continued:
+ // Will wake up anyone sitting in waitFor
+ log.debug("continuing with {}", userAuth);
+ break;
+ }
+ }
+
+ public CloseFuture close(boolean immediately) {
+ if (!authFuture.isDone()) {
+ authFuture.setException(new SshException("Session is closed"));
+ }
+ CloseFuture future = new DefaultCloseFuture(lock);
+ future.setClosed();
+ return future;
+ }
+
+ public AuthFuture auth(UserAuth userAuth) throws IOException {
+ log.debug("Trying authentication with {}", userAuth);
+ synchronized (lock) {
+ if (readyForAuth(userAuth)) {
+ processUserAuth(null);
+ }
+ return authFuture;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java \
b/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java index \
63b87c2..70a379e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/KeyPairProvider.java
@@ -54,6 +54,13 @@ public interface KeyPairProvider {
String ECDSA_SHA2_NISTP521 = "ecdsa-sha2-nistp521";
/**
+ * Load available keys.
+ *
+ * @return an array of available keys, never <code>null</code>
+ */
+ KeyPair[] loadKeys();
+
+ /**
* Load a key of the specified type which can be "ssh-rsa", "ssh-dss", or
* "ecdsa-sha2-nistp{256,384,521}". If there is no key of this type, return
* <code>null</code>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java \
b/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java index \
bb0cf45..0cb5f3e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
@@ -53,10 +53,14 @@ public interface SshConstants {
static final byte SSH_MSG_USERAUTH_FAILURE= 51;
static final byte SSH_MSG_USERAUTH_SUCCESS= 52;
static final byte SSH_MSG_USERAUTH_BANNER= 53;
+
static final byte SSH_MSG_USERAUTH_INFO_REQUEST= 60;
static final byte SSH_MSG_USERAUTH_INFO_RESPONSE= 61;
+
static final byte SSH_MSG_USERAUTH_PK_OK= 60;
+ static final byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ= 60;
+
static final byte SSH_MSG_USERAUTH_GSSAPI_MIC= 66;
static final byte SSH_MSG_GLOBAL_REQUEST= 80;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java \
b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
index 0337e87..bf6650b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractKeyPairProvider.java
@@ -19,10 +19,6 @@
package org.apache.sshd.common.keyprovider;
import java.security.KeyPair;
-import java.security.interfaces.DSAKey;
-import java.security.interfaces.ECKey;
-import java.security.interfaces.RSAKey;
-import java.security.spec.ECParameterSpec;
import java.util.ArrayList;
import java.util.List;
@@ -30,6 +26,8 @@ import org.apache.sshd.common.KeyPairProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.apache.sshd.common.util.KeyUtils.getKeyType;
+
/**
* TODO Add javadoc
*
@@ -69,30 +67,5 @@ public abstract class AbstractKeyPairProvider implements \
KeyPairProvider { return sb.toString();
}
- protected String getKeyType(KeyPair kp) {
- Object key = kp.getPrivate() != null ? kp.getPrivate() : kp.getPublic();
- if (key instanceof DSAKey) {
- return SSH_DSS;
- } else if (key instanceof RSAKey) {
- return SSH_RSA;
- } else if (key instanceof ECKey) {
- ECKey ecKey = (ECKey) key;
- ECParameterSpec ecSpec = ecKey.getParams();
- /*
- * TODO make this more robust by checking the actual parameters instead \
of
- * just the field size.
- */
- switch (ecSpec.getCurve().getField().getFieldSize()) {
- case 256:
- return ECDSA_SHA2_NISTP256;
- case 384:
- return ECDSA_SHA2_NISTP384;
- case 521:
- return ECDSA_SHA2_NISTP521;
- }
- }
- return null;
- }
-
- protected abstract KeyPair[] loadKeys();
+ public abstract KeyPair[] loadKeys();
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java \
b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java index \
cc050e2..e6d1639 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
@@ -255,9 +255,12 @@ public abstract class AbstractSession implements Session {
return authed;
}
- public void setAuthenticated(String username) throws IOException {
- this.authed = true;
+ public void setUsername(String username) {
this.username = username;
+ }
+
+ public void setAuthenticated() throws IOException {
+ this.authed = true;
sendEvent(SessionListener.Event.Authenticated);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/common/util/KeyUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/KeyUtils.java \
b/sshd-core/src/main/java/org/apache/sshd/common/util/KeyUtils.java index \
cd9fd65..123d594 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/KeyUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/KeyUtils.java
@@ -18,8 +18,15 @@
*/
package org.apache.sshd.common.util;
+import java.security.Key;
+import java.security.KeyPair;
import java.security.PublicKey;
+import java.security.interfaces.DSAKey;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
+import java.security.spec.ECParameterSpec;
+import org.apache.sshd.common.KeyPairProvider;
import org.apache.sshd.common.digest.MD5;
/**
@@ -49,6 +56,46 @@ public class KeyUtils {
}
}
+ /**
+ * Retrieve the key type
+ *
+ * @param kp a key pair
+ * @return the key type
+ */
+ public static String getKeyType(KeyPair kp) {
+ return getKeyType(kp.getPrivate() != null ? kp.getPrivate() : \
kp.getPublic()); + }
+
+ /**
+ * Retrieve the key type
+ *
+ * @param key a public or private key
+ * @return the key type
+ */
+ public static String getKeyType(Key key) {
+ if (key instanceof DSAKey) {
+ return KeyPairProvider.SSH_DSS;
+ } else if (key instanceof RSAKey) {
+ return KeyPairProvider.SSH_RSA;
+ } else if (key instanceof ECKey) {
+ ECKey ecKey = (ECKey) key;
+ ECParameterSpec ecSpec = ecKey.getParams();
+ /*
+ * TODO make this more robust by checking the actual parameters instead \
of + * just the field size.
+ */
+ switch (ecSpec.getCurve().getField().getFieldSize()) {
+ case 256:
+ return KeyPairProvider.ECDSA_SHA2_NISTP256;
+ case 384:
+ return KeyPairProvider.ECDSA_SHA2_NISTP384;
+ case 521:
+ return KeyPairProvider.ECDSA_SHA2_NISTP521;
+ }
+ }
+ return null;
+ }
+
private KeyUtils() {
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java \
b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
index 94cfdba..e0e7152 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthKeyboardInteractive.java
@@ -44,9 +44,6 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth \
{
@Override
protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
- if (!"ssh-connection".equals(service)) {
- throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, \
"Unsupported service '" + service + "'");
- }
if (init) {
// Prompt for password
buffer = \
session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, 0);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/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 \
50754ac..6219c3a 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
@@ -46,9 +46,6 @@ public class UserAuthPassword extends AbstractUserAuth {
if (!init) {
throw new IllegalStateException();
}
- 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/0824b93b/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 \
0e4de86..3f4971a 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
@@ -50,9 +50,6 @@ public class UserAuthPublicKey extends AbstractUserAuth {
if (!init) {
throw new IllegalStateException();
}
- if (!"ssh-connection".equals(service)) {
- throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, \
"Unsupported service '" + service + "'");
- }
boolean hasSig = buffer.getBoolean();
String alg = buffer.getString();
@@ -88,7 +85,7 @@ public class UserAuthPublicKey extends AbstractUserAuth {
buf.putString(session.getKex().getH());
buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
buf.putString(username);
- buf.putString("ssh-connection");
+ buf.putString(service);
buf.putString("publickey");
buf.putByte((byte) 1);
buf.putString(keyAlg);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java \
b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java \
index 49612e2..5f7dd19 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
@@ -129,6 +129,7 @@ public class ServerUserAuthService implements Service {
+ username + ", " + service + ")");
return;
}
+ // TODO: verify that the service is supported
this.authMethod = method;
if (nbAuthRequests++ > maxAuthRequests) {
session.disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too \
many authentication failures"); @@ -197,7 +198,8 @@ public class \
ServerUserAuthService implements Service {
buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_SUCCESS, \
0); session.writePacket(buffer);
- session.setAuthenticated(username);
+ session.setUsername(username);
+ session.setAuthenticated();
session.startService(authService);
session.resetIdleTimeout();
log.info("Session {}@{} authenticated", username, \
session.getIoSession().getRemoteAddress());
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/ClientTest.java \
b/sshd-core/src/test/java/org/apache/sshd/ClientTest.java index 6fc48e5..6e0de51 \
100644
--- a/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
@@ -364,6 +364,26 @@ public class ClientTest {
}
@Test
+ public void testPublicKeyAuthNew() throws Exception {
+ SshClient client = SshClient.setUpDefaultClient();
+ client.start();
+ ClientSession session = client.connect("smx", "localhost", \
port).await().getSession(); + KeyPair pair = \
Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA); + \
session.addPublicKeyIdentity(pair); + session.auth().verify();
+ }
+
+ @Test
+ public void testPasswordAuthNew() throws Exception {
+ SshClient client = SshClient.setUpDefaultClient();
+ client.start();
+ ClientSession session = client.connect("smx", "localhost", \
port).await().getSession(); + KeyPair pair = \
Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA); + \
session.addPasswordIdentity("smx"); + session.auth().verify();
+ }
+
+ @Test
public void testClientDisconnect() throws Exception {
TestEchoShellFactory.TestEchoShell.latch = new CountDownLatch(1);
try
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic