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 2014/01/31 11:52:11 UTC
[2/3] git commit: [SSHD-235][SSHD-287] Refactor client side
authentication API, support partial authentication
[SSHD-235][SSHD-287] Refactor client side authentication API, support partial authentication
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/0824b93b
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/0824b93b
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/0824b93b
Branch: refs/heads/master
Commit: 0824b93bdde6782ecb2669fed808c3137db74af8
Parents: d5b96d9
Author: Guillaume Nodet <gn...@apache.org>
Authored: Fri Jan 31 11:50:32 2014 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Fri Jan 31 11:51:25 2014 +0100
----------------------------------------------------------------------
.../java/org/apache/sshd/ClientSession.java | 10 +
.../main/java/org/apache/sshd/SshClient.java | 33 ++-
.../sshd/client/ClientFactoryManager.java | 17 ++
.../java/org/apache/sshd/client/UserAuth.java | 13 +-
.../sshd/client/auth/AbstractUserAuth.java | 50 ----
.../apache/sshd/client/auth/UserAuthAgent.java | 117 ----------
.../auth/UserAuthKeyboardInteractive.java | 142 +++++++-----
.../sshd/client/auth/UserAuthPassword.java | 85 ++++---
.../sshd/client/auth/UserAuthPublicKey.java | 203 ++++++++++++-----
.../auth/deprecated/AbstractUserAuth.java | 43 ++++
.../sshd/client/auth/deprecated/UserAuth.java | 40 ++++
.../client/auth/deprecated/UserAuthAgent.java | 117 ++++++++++
.../deprecated/UserAuthKeyboardInteractive.java | 111 +++++++++
.../auth/deprecated/UserAuthPassword.java | 72 ++++++
.../auth/deprecated/UserAuthPublicKey.java | 107 +++++++++
.../apache/sshd/client/future/AuthFuture.java | 8 +
.../sshd/client/future/DefaultAuthFuture.java | 13 ++
.../sshd/client/session/ClientSessionImpl.java | 41 +++-
.../client/session/ClientUserAuthService.java | 156 ++++---------
.../session/ClientUserAuthServiceNew.java | 227 +++++++++++++++++++
.../session/ClientUserAuthServiceOld.java | 189 +++++++++++++++
.../org/apache/sshd/common/KeyPairProvider.java | 7 +
.../org/apache/sshd/common/SshConstants.java | 4 +
.../keyprovider/AbstractKeyPairProvider.java | 33 +--
.../sshd/common/session/AbstractSession.java | 7 +-
.../org/apache/sshd/common/util/KeyUtils.java | 47 ++++
.../auth/UserAuthKeyboardInteractive.java | 3 -
.../sshd/server/auth/UserAuthPassword.java | 3 -
.../sshd/server/auth/UserAuthPublicKey.java | 5 +-
.../server/session/ServerUserAuthService.java | 4 +-
.../test/java/org/apache/sshd/ClientTest.java | 20 ++
31 files changed, 1435 insertions(+), 492 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
index 96068cb..15b0005 100644
--- a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
@@ -31,6 +31,7 @@ import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.channel.ChannelSubsystem;
import org.apache.sshd.client.future.AuthFuture;
import org.apache.sshd.common.Session;
+import org.apache.sshd.common.SshException;
import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.future.CloseFuture;
@@ -62,24 +63,33 @@ public interface ClientSession extends Session {
int WAIT_AUTH = 0x0004;
int AUTHED = 0x0008;
+ void addPasswordIdentity(String password);
+ void addPublicKeyIdentity(KeyPair key);
+
+ AuthFuture auth() throws IOException;
+
/**
* Authenticate the session with the given username using an ssh agent.
*/
+ @Deprecated
AuthFuture authAgent(String username) throws IOException;
/**
* Authenticate the session with the given username and password.
*/
+ @Deprecated
AuthFuture authPassword(String username, String password) throws IOException;
/**
* Authenticate the session with the given username and password.
*/
+ @Deprecated
AuthFuture authInteractive(String username, String password) throws IOException;
/**
* Authenticate the session with the given username and public key.
*/
+ @Deprecated
AuthFuture authPublicKey(String username, KeyPair key) throws IOException;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/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 8d4e169..f0858eb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
@@ -38,7 +38,11 @@ import java.util.concurrent.Executors;
import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.SessionFactory;
+import org.apache.sshd.client.UserAuth;
import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.auth.UserAuthKeyboardInteractive;
+import org.apache.sshd.client.auth.UserAuthPassword;
+import org.apache.sshd.client.auth.UserAuthPublicKey;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.future.AuthFuture;
import org.apache.sshd.client.future.ConnectFuture;
@@ -149,6 +153,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
protected SessionFactory sessionFactory;
protected UserInteraction userInteraction;
protected Factory<IoConnector> connectorFactory;
+ protected List<NamedFactory<UserAuth>> userAuthFactories;
private ServerKeyVerifier serverKeyVerifier;
@@ -179,6 +184,14 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
this.userInteraction = userInteraction;
}
+ public List<NamedFactory<UserAuth>> getUserAuthFactories() {
+ return userAuthFactories;
+ }
+
+ public void setUserAuthFactories(List<NamedFactory<UserAuth>> userAuthFactories) {
+ this.userAuthFactories = userAuthFactories;
+ }
+
protected void checkConfig() {
if (getKeyExchangeFactories() == null) {
throw new IllegalArgumentException("KeyExchangeFactories not set");
@@ -224,6 +237,13 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
new ClientConnectionService.Factory()
));
}
+ if (getUserAuthFactories() == null) {
+ setUserAuthFactories(Arrays.asList(
+ new UserAuthPublicKey.Factory(),
+ new UserAuthKeyboardInteractive.Factory(),
+ new UserAuthPassword.Factory()
+ ));
+ }
}
public void start() {
@@ -244,17 +264,27 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
}
}
+ @Deprecated
public ConnectFuture connect(String host, int port) throws IOException {
+ return connect(null, host, port);
+ }
+
+ public ConnectFuture connect(String username, String host, int port) throws IOException {
assert host != null;
assert port >= 0;
if (connector == null) {
throw new IllegalStateException("SshClient not started. Please call start() method before connecting to a server");
}
SocketAddress address = new InetSocketAddress(host, port);
- return connect(address);
+ return connect(username, address);
}
+ @Deprecated
public ConnectFuture connect(SocketAddress address) {
+ return connect(null, address);
+ }
+
+ public ConnectFuture connect(final String username, SocketAddress address) {
assert address != null;
if (connector == null) {
throw new IllegalStateException("SshClient not started. Please call start() method before connecting to a server");
@@ -268,6 +298,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
connectFuture.setException(future.getException());
} else {
ClientSessionImpl session = (ClientSessionImpl) AbstractSession.getSession(future.getSession());
+ session.setUsername(username);
connectFuture.setSession(session);
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/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 8375ffa..595dc93 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
@@ -18,7 +18,10 @@
*/
package org.apache.sshd.client;
+import java.util.List;
+
import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.TcpipForwarderFactory;
/**
@@ -40,6 +43,12 @@ public interface ClientFactoryManager extends FactoryManager {
public static final String HEARTBEAT_REQUEST = "heartbeat-request";
/**
+ * Ordered comma separated list of authentications methods.
+ * Authentications methods accepted by the server will be tried in the given order.
+ */
+ public static final String PREFERRED_AUTHS = "preferred-auths";
+
+ /**
* Retrieve the server key verifier to be used to check the key when connecting
* to an ssh server.
*
@@ -61,4 +70,12 @@ public interface ClientFactoryManager extends FactoryManager {
* @return A <code>UserInteraction</code> or <code>null</code>
*/
UserInteraction getUserInteraction();
+
+ /**
+ * Retrieve a list of UserAuth factories.
+ *
+ * @return a list of named <code>UserAuth</code> factories, never <code>null</code>
+ */
+ List<NamedFactory<UserAuth>> getUserAuthFactories();
+
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java b/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java
index f508509..a2e8cb7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java
@@ -18,8 +18,9 @@
*/
package org.apache.sshd.client;
-import java.io.IOException;
+import java.util.List;
+import org.apache.sshd.ClientSession;
import org.apache.sshd.common.util.Buffer;
/**
@@ -29,14 +30,10 @@ import org.apache.sshd.common.util.Buffer;
*/
public interface UserAuth {
- enum Result {
- Success,
- Failure,
- Continued
- }
+ void init(ClientSession session, String service, List<Object> identities) throws Exception;
- String getUsername();
+ boolean process(Buffer buffer) throws Exception;
- Result next(Buffer buffer) throws IOException;
+ void destroy();
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java
deleted file mode 100644
index 5f9a346..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/AbstractUserAuth.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-import org.apache.sshd.client.UserAuth;
-import org.apache.sshd.client.session.ClientSessionImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- */
-public abstract class AbstractUserAuth implements UserAuth {
-
- protected final Logger log = LoggerFactory.getLogger(this.getClass());
-
- protected final ClientSessionImpl session;
- protected final String service;
- protected final String username;
-
- protected AbstractUserAuth(ClientSessionImpl session, String service, String username) {
- this.session = session;
- this.username = username;
- this.service = service;
- }
-
- public String getUsername() {
- return username;
- }
-
- public String getService() {
- return service;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthAgent.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthAgent.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthAgent.java
deleted file mode 100644
index 7ceac6a..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthAgent.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.auth;
-
-import java.io.IOException;
-import java.security.PublicKey;
-import java.security.interfaces.RSAPublicKey;
-import java.util.Iterator;
-
-import org.apache.sshd.agent.SshAgent;
-import org.apache.sshd.client.session.ClientSessionImpl;
-import org.apache.sshd.common.KeyPairProvider;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.Buffer;
-
-/**
- * Authentication delegating to an SSH agent
- */
-public class UserAuthAgent extends AbstractUserAuth {
-
- private final SshAgent agent;
- private final Iterator<SshAgent.Pair<PublicKey, String>> keys;
-
- public UserAuthAgent(ClientSessionImpl session, String service, String username) throws IOException {
- super(session, service, username);
- if (session.getFactoryManager().getAgentFactory() == null) {
- throw new IllegalStateException("No ssh agent factory has been configured");
- }
- this.agent = session.getFactoryManager().getAgentFactory().createClient(session.getFactoryManager());
- this.keys = agent.getIdentities().iterator();
- }
-
- protected void sendNextKey(PublicKey key) throws IOException {
- try {
- log.info("Send SSH_MSG_USERAUTH_REQUEST for publickey");
- Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
- int pos1 = buffer.wpos() - 1;
- buffer.putString(username);
- buffer.putString(service);
- buffer.putString("publickey");
- buffer.putByte((byte) 1);
- buffer.putString((key instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
- int pos2 = buffer.wpos();
- buffer.putPublicKey(key);
-
-
- Buffer bs = new Buffer();
- bs.putString(session.getKex().getH());
- bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
- bs.putString(username);
- bs.putString(service);
- bs.putString("publickey");
- bs.putByte((byte) 1);
- bs.putString((key instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
- bs.putPublicKey(key);
-
- Buffer bs2 = new Buffer();
- bs2.putString((key instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
- bs2.putBytes(agent.sign(key, bs.getCompactData()));
- buffer.putBytes(bs2.array(), bs2.rpos(), bs2.available());
-
- session.writePacket(buffer);
- } catch (IOException e) {
- throw e;
- } catch (Exception e) {
- throw (IOException) new IOException("Error performing public key authentication").initCause(e);
- }
- }
-
- public Result next(Buffer buffer) throws IOException {
- if (buffer == null) {
- if (keys.hasNext()) {
- sendNextKey(keys.next().getFirst());
- return Result.Continued;
- } else {
- agent.close();
- return Result.Failure;
- }
- } else {
- byte cmd = buffer.getByte();
- if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
- log.info("Received SSH_MSG_USERAUTH_SUCCESS");
- agent.close();
- return Result.Success;
- } if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
- log.info("Received SSH_MSG_USERAUTH_FAILURE");
- if (keys.hasNext()) {
- sendNextKey(keys.next().getFirst());
- return Result.Continued;
- } else {
- agent.close();
- return Result.Failure;
- }
- } else {
- // TODO: check packets
- log.info("Received unknown packet: {}", cmd);
- return Result.Continued;
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
index 374ac36..d25b133 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
@@ -18,94 +18,110 @@
*/
package org.apache.sshd.client.auth;
-import java.io.IOException;
+import java.util.List;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.client.UserAuth;
import org.apache.sshd.client.UserInteraction;
-import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.client.session.ClientUserAuthServiceNew;
+import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.session.AbstractSession;
import org.apache.sshd.common.util.Buffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import static org.apache.sshd.common.SshConstants.*;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE;
/**
- * Userauth with keyboard-interactive method.
+ * TODO Add javadoc
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- * @author <a href="mailto:j.kapitza@schwarze-allianz.de">Jens Kapitza</a>
*/
-public class UserAuthKeyboardInteractive extends AbstractUserAuth {
+public class UserAuthKeyboardInteractive implements UserAuth {
- private final String password;
+ public static class Factory implements NamedFactory<UserAuth> {
+ public String getName() {
+ return "keyboard-interactive";
+ }
+ public UserAuth create() {
+ return new UserAuthKeyboardInteractive();
+ }
+ }
- public UserAuthKeyboardInteractive(ClientSessionImpl session, String service, String username, String password) {
- super(session, service, username);
- this.password = password;
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ private ClientSession session;
+ private String service;
+ private String password;
+
+ public void init(ClientSession session, String service, List<Object> identities) throws Exception {
+ this.session = session;
+ this.service = service;
+ for (Object o : identities) {
+ if (o instanceof String) {
+ password = (String) o;
+ break;
+ }
+ }
}
- public Result next(Buffer buffer) throws IOException {
+ public boolean process(Buffer buffer) throws Exception {
if (buffer == null) {
log.info("Send SSH_MSG_USERAUTH_REQUEST for password");
buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
- buffer.putString(username);
+ buffer.putString(session.getUsername());
buffer.putString(service);
buffer.putString("keyboard-interactive");
buffer.putString("");
buffer.putString("");
session.writePacket(buffer);
- return Result.Continued;
- } else {
- byte cmd = buffer.getByte();
- switch (cmd) {
- case SSH_MSG_USERAUTH_INFO_REQUEST:
- log.info("Received SSH_MSG_USERAUTH_INFO_REQUEST");
- String name = buffer.getString();
- String instruction = buffer.getString();
- String language_tag = buffer.getString();
- log.info("Received {} {} {}", new Object[]{name, instruction, language_tag});
- int num = buffer.getInt();
- String[] prompt = new String[num];
- boolean[] echo = new boolean[num];
- for (int i = 0; i < num; i++) {
- prompt[i] = buffer.getString();
- echo[i] = (buffer.getByte() != 0);
- }
- log.info("Promt: {}", prompt);
- log.info("Echo: {}", echo);
+ return true;
+ }
+ byte cmd = buffer.getByte();
+ if (cmd == SSH_MSG_USERAUTH_INFO_REQUEST) {
+ log.info("Received SSH_MSG_USERAUTH_INFO_REQUEST");
+ String name = buffer.getString();
+ String instruction = buffer.getString();
+ String language_tag = buffer.getString();
+ log.info("Received {} {} {}", new Object[]{name, instruction, language_tag});
+ int num = buffer.getInt();
+ String[] prompt = new String[num];
+ boolean[] echo = new boolean[num];
+ for (int i = 0; i < num; i++) {
+ prompt[i] = buffer.getString();
+ echo[i] = (buffer.getByte() != 0);
+ }
+ log.info("Promt: {}", prompt);
+ log.info("Echo: {}", echo);
- String[] rep = null;
- if (num == 0) {
- rep = new String[0];
- } else if (num == 1 && password != null && !echo[0] && prompt[0].toLowerCase().startsWith("password:")) {
- rep = new String[] { password };
- } else {
- UserInteraction ui = session.getFactoryManager().getUserInteraction();
- if (ui != null) {
- String dest = username + "@" + session.getIoSession().getRemoteAddress().toString();
- rep = ui.interactive(dest, name, instruction, prompt, echo);
- }
- }
- if (rep == null) {
- return Result.Failure;
- }
+ String[] rep = null;
+ if (num == 0) {
+ rep = new String[0];
+ } else if (num == 1 && password != null && !echo[0] && prompt[0].toLowerCase().startsWith("password:")) {
+ rep = new String[] { password };
+ } else {
+ UserInteraction ui = session.getFactoryManager().getUserInteraction();
+ if (ui != null) {
+ String dest = session.getUsername() + "@" + ((AbstractSession) session).getIoSession().getRemoteAddress().toString();
+ rep = ui.interactive(dest, name, instruction, prompt, echo);
+ }
+ }
+ if (rep == null) {
+ return false;
+ }
- buffer = session.createBuffer(SSH_MSG_USERAUTH_INFO_RESPONSE, 0);
- buffer.putInt(rep.length);
- for (String r : rep) {
- buffer.putString(r);
- }
- session.writePacket(buffer);
- return Result.Continued;
- case SSH_MSG_USERAUTH_SUCCESS:
- log.info("Received SSH_MSG_USERAUTH_SUCCESS");
- return Result.Success;
- case SSH_MSG_USERAUTH_FAILURE:
- log.info("Received SSH_MSG_USERAUTH_FAILURE");
- return Result.Failure;
- default:
- log.info("Received unknown packet {}", cmd);
- return Result.Continued;
+ buffer = session.createBuffer(SSH_MSG_USERAUTH_INFO_RESPONSE, 0);
+ buffer.putInt(rep.length);
+ for (String r : rep) {
+ buffer.putString(r);
}
+ session.writePacket(buffer);
+ return true;
}
+ throw new IllegalStateException("Received unknown packet");
}
-}
\ No newline at end of file
+ public void destroy() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
index 900e36c..114bdcd 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
@@ -18,10 +18,14 @@
*/
package org.apache.sshd.client.auth;
-import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.sshd.ClientSession;
import org.apache.sshd.client.UserAuth;
-import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.client.session.ClientUserAuthServiceNew;
+import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.util.Buffer;
import org.slf4j.Logger;
@@ -32,42 +36,63 @@ import org.slf4j.LoggerFactory;
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class UserAuthPassword extends AbstractUserAuth {
+public class UserAuthPassword implements UserAuth {
- protected final Logger log = LoggerFactory.getLogger(getClass());
+ public static class Factory implements NamedFactory<UserAuth> {
+ public String getName() {
+ return "password";
+ }
+ public UserAuth create() {
+ return new UserAuthPassword();
+ }
+ }
- private final String password;
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ private ClientSession session;
+ private String service;
+ private Iterator<String> passwords;
+ private String current;
- public UserAuthPassword(ClientSessionImpl session, String service, String username, String password) {
- super(session, service, username);
- this.password = password;
+ public void init(ClientSession session, String service, List<Object> identities) throws Exception {
+ this.session = session;
+ this.service = service;
+ List<String> pwds = new ArrayList<String>();
+ for (Object o : identities) {
+ if (o instanceof String) {
+ pwds.add((String) o);
+ }
+ }
+ this.passwords = pwds.iterator();
}
- public Result next(Buffer buffer) throws IOException {
+ public boolean process(Buffer buffer) throws Exception {
+ // Send next key
if (buffer == null) {
- log.info("Send SSH_MSG_USERAUTH_REQUEST for password");
- buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
- buffer.putString(username);
- buffer.putString(service);
- buffer.putString("password");
- buffer.putByte((byte) 0);
- buffer.putString(password);
- session.writePacket(buffer);
- return Result.Continued;
- } else {
- byte cmd = buffer.getByte();
- if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
- log.info("Received SSH_MSG_USERAUTH_SUCCESS");
- return Result.Success;
- } if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
- log.info("Received SSH_MSG_USERAUTH_FAILURE");
- return Result.Failure;
- } else {
- log.info("Received unkown packet {}", cmd);
- // TODO: check packets
- return Result.Continued;
+ if (passwords.hasNext()) {
+ current = passwords.next();
+ log.info("Send SSH_MSG_USERAUTH_REQUEST for password");
+ buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
+ buffer.putString(session.getUsername());
+ buffer.putString(service);
+ buffer.putString("password");
+ buffer.putByte((byte) 0);
+ buffer.putString(current);
+ session.writePacket(buffer);
+ return true;
}
+ return false;
}
+ byte cmd = buffer.getByte();
+ if (cmd == SshConstants.SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
+ String prompt = buffer.getString();
+ String lang = buffer.getString();
+ // TODO: prompt user for password change
+ log.warn("Password change requested, but not supported");
+ return false;
+ }
+ throw new IllegalStateException("Received unknown packet");
}
+ public void destroy() {
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
index 9804d2f..a24c7b5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
@@ -18,89 +18,182 @@
*/
package org.apache.sshd.client.auth;
-import java.io.IOException;
import java.security.KeyPair;
-import java.security.interfaces.RSAPublicKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.agent.SshAgentFactory;
import org.apache.sshd.client.UserAuth;
-import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.client.session.ClientUserAuthServiceNew;
+import org.apache.sshd.common.FactoryManager;
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.session.AbstractSession;
import org.apache.sshd.common.util.Buffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.apache.sshd.common.util.KeyUtils.getKeyType;
+
/**
* TODO Add javadoc
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class UserAuthPublicKey extends AbstractUserAuth {
+public class UserAuthPublicKey implements UserAuth {
- protected final Logger log = LoggerFactory.getLogger(getClass());
+ public static class Factory implements NamedFactory<UserAuth> {
+ public String getName() {
+ return "publickey";
+ }
+ public UserAuth create() {
+ return new UserAuthPublicKey();
+ }
+ }
- private final KeyPair key;
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ private ClientSession session;
+ private String service;
+ private SshAgent agent;
+ private Iterator<PublicKeyIdentity> keys;
+ private PublicKeyIdentity current;
- public UserAuthPublicKey(ClientSessionImpl session, String service, String username, KeyPair key) {
- super(session, service, username);
- this.key = key;
+ public void init(ClientSession session, String service, List<Object> identities) throws Exception {
+ this.session = session;
+ this.service = service;
+ List<PublicKeyIdentity> ids = new ArrayList<PublicKeyIdentity>();
+ for (Object o : identities) {
+ if (o instanceof KeyPair) {
+ ids.add(new KeyPairIdentity(session.getFactoryManager(), (KeyPair) o));
+ }
+ }
+ KeyPairProvider provider = session.getFactoryManager().getKeyPairProvider();
+ if (provider != null) {
+ for (KeyPair pair : provider.loadKeys()) {
+ ids.add(new KeyPairIdentity(session.getFactoryManager(), pair));
+ }
+ }
+ SshAgentFactory factory = session.getFactoryManager().getAgentFactory();
+ if (factory != null) {
+ this.agent = factory.createClient(session.getFactoryManager());
+ for (SshAgent.Pair<PublicKey, String> pair : agent.getIdentities()) {
+ ids.add(new KeyAgentIdentity(agent, pair.getFirst()));
+ }
+ } else {
+ this.agent = null;
+ }
+ this.keys = ids.iterator();
}
- public Result next(Buffer buffer) throws IOException {
+ public boolean process(Buffer buffer) throws Exception {
+ // Send next key
if (buffer == null) {
- try {
+ if (keys.hasNext()) {
+ current = keys.next();
+ PublicKey key = current.getPublicKey();
+ String algo = getKeyType(key);
log.info("Send SSH_MSG_USERAUTH_REQUEST for publickey");
buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
- int pos1 = buffer.wpos() - 1;
- buffer.putString(username);
+ buffer.putString(session.getUsername());
buffer.putString(service);
buffer.putString("publickey");
- buffer.putByte((byte) 1);
- buffer.putString((key.getPublic() instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
- int pos2 = buffer.wpos();
- buffer.putPublicKey(key.getPublic());
-
- Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), (key.getPublic() instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
- verif.init(key.getPublic(), key.getPrivate());
-
- Buffer bs = new Buffer();
- bs.putString(session.getKex().getH());
- bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
- bs.putString(username);
- bs.putString(service);
- bs.putString("publickey");
- bs.putByte((byte) 1);
- bs.putString((key.getPublic() instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
- bs.putPublicKey(key.getPublic());
- verif.update(bs.array(), bs.rpos(), bs.available());
-
- bs = new Buffer();
- bs.putString((key.getPublic() instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
- bs.putBytes(verif.sign());
- buffer.putBytes(bs.array(), bs.rpos(), bs.available());
-
+ buffer.putByte((byte) 0);
+ buffer.putString(algo);
+ buffer.putPublicKey(key);
session.writePacket(buffer);
- return Result.Continued;
- } catch (IOException e) {
- throw e;
- } catch (Exception e) {
- throw (IOException) new IOException("Error performing public key authentication").initCause(e);
- }
- } else {
- byte cmd = buffer.getByte();
- if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
- log.info("Received SSH_MSG_USERAUTH_SUCCESS");
- return Result.Success;
- } if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
- log.info("Received SSH_MSG_USERAUTH_FAILURE");
- return Result.Failure;
- } else {
- log.info("Received unknown packet {}", cmd);
- // TODO: check packets
- return Result.Continued;
+ return true;
}
+ return false;
+ }
+ byte cmd = buffer.getByte();
+ if (cmd == SshConstants.SSH_MSG_USERAUTH_PK_OK) {
+ PublicKey key = current.getPublicKey();
+ String algo = getKeyType(key);
+ log.info("Send SSH_MSG_USERAUTH_REQUEST for publickey");
+ buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
+ buffer.putString(session.getUsername());
+ buffer.putString(service);
+ buffer.putString("publickey");
+ buffer.putByte((byte) 1);
+ buffer.putString(algo);
+ buffer.putPublicKey(key);
+
+ Buffer bs = new Buffer();
+ bs.putString(((AbstractSession) session).getKex().getH());
+ bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+ bs.putString(session.getUsername());
+ bs.putString(service);
+ bs.putString("publickey");
+ bs.putByte((byte) 1);
+ bs.putString(algo);
+ bs.putPublicKey(key);
+ byte[] sig = current.sign(bs.getCompactData());
+
+ bs = new Buffer();
+ bs.putString(algo);
+ bs.putBytes(sig);
+ buffer.putBytes(bs.array(), bs.rpos(), bs.available());
+
+ session.writePacket(buffer);
+ return true;
+ }
+
+ throw new IllegalStateException("Received unknown packet");
+ }
+
+ public void destroy() {
+ if (agent != null) {
+ agent.close();
+ }
+ }
+
+ interface PublicKeyIdentity {
+ PublicKey getPublicKey();
+ byte[] sign(byte[] data) throws Exception;
+ }
+
+ static class KeyAgentIdentity implements PublicKeyIdentity {
+ private final SshAgent agent;
+ private final PublicKey key;
+
+ KeyAgentIdentity(SshAgent agent, PublicKey key) {
+ this.agent = agent;
+ this.key = key;
+ }
+
+ public PublicKey getPublicKey() {
+ return key;
+ }
+
+ public byte[] sign(byte[] data) throws Exception {
+ return agent.sign(key, data);
+ }
+ }
+
+ static class KeyPairIdentity implements PublicKeyIdentity {
+ private final KeyPair pair;
+ private final FactoryManager manager;
+
+ KeyPairIdentity(FactoryManager manager, KeyPair pair) {
+ this.manager = manager;
+ this.pair = pair;
+ }
+
+ public PublicKey getPublicKey() {
+ return pair.getPublic();
+ }
+
+ public byte[] sign(byte[] data) throws Exception {
+ Signature verif = NamedFactory.Utils.create(manager.getSignatureFactories(), getKeyType(pair));
+ verif.init(pair.getPublic(), pair.getPrivate());
+ verif.update(data, 0, data.length);
+ return verif.sign();
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/AbstractUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/AbstractUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/AbstractUserAuth.java
new file mode 100644
index 0000000..d847283
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/AbstractUserAuth.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client.auth.deprecated;
+
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public abstract class AbstractUserAuth implements UserAuth {
+
+ protected final Logger log = LoggerFactory.getLogger(this.getClass());
+
+ protected final ClientSessionImpl session;
+ protected final String service;
+
+ protected AbstractUserAuth(ClientSessionImpl session, String service) {
+ this.session = session;
+ this.service = service;
+ }
+
+ public String getService() {
+ return service;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuth.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuth.java
new file mode 100644
index 0000000..af354ee
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuth.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client.auth.deprecated;
+
+import java.io.IOException;
+
+import org.apache.sshd.common.util.Buffer;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface UserAuth {
+
+ enum Result {
+ Success,
+ Failure,
+ Continued
+ }
+
+ Result next(Buffer buffer) throws IOException;
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthAgent.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthAgent.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthAgent.java
new file mode 100644
index 0000000..7ef6234
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthAgent.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client.auth.deprecated;
+
+import java.io.IOException;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Iterator;
+
+import org.apache.sshd.agent.SshAgent;
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.Buffer;
+
+/**
+ * Authentication delegating to an SSH agent
+ */
+public class UserAuthAgent extends AbstractUserAuth {
+
+ private final SshAgent agent;
+ private final Iterator<SshAgent.Pair<PublicKey, String>> keys;
+
+ public UserAuthAgent(ClientSessionImpl session, String service) throws IOException {
+ super(session, service);
+ if (session.getFactoryManager().getAgentFactory() == null) {
+ throw new IllegalStateException("No ssh agent factory has been configured");
+ }
+ this.agent = session.getFactoryManager().getAgentFactory().createClient(session.getFactoryManager());
+ this.keys = agent.getIdentities().iterator();
+ }
+
+ protected void sendNextKey(PublicKey key) throws IOException {
+ try {
+ log.info("Send SSH_MSG_USERAUTH_REQUEST for publickey");
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
+ int pos1 = buffer.wpos() - 1;
+ buffer.putString(session.getUsername());
+ buffer.putString(service);
+ buffer.putString("publickey");
+ buffer.putByte((byte) 1);
+ buffer.putString((key instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
+ int pos2 = buffer.wpos();
+ buffer.putPublicKey(key);
+
+
+ Buffer bs = new Buffer();
+ bs.putString(session.getKex().getH());
+ bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+ bs.putString(session.getUsername());
+ bs.putString(service);
+ bs.putString("publickey");
+ bs.putByte((byte) 1);
+ bs.putString((key instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
+ bs.putPublicKey(key);
+
+ Buffer bs2 = new Buffer();
+ bs2.putString((key instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
+ bs2.putBytes(agent.sign(key, bs.getCompactData()));
+ buffer.putBytes(bs2.array(), bs2.rpos(), bs2.available());
+
+ session.writePacket(buffer);
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw (IOException) new IOException("Error performing public key authentication").initCause(e);
+ }
+ }
+
+ public Result next(Buffer buffer) throws IOException {
+ if (buffer == null) {
+ if (keys.hasNext()) {
+ sendNextKey(keys.next().getFirst());
+ return Result.Continued;
+ } else {
+ agent.close();
+ return Result.Failure;
+ }
+ } else {
+ byte cmd = buffer.getByte();
+ if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
+ log.info("Received SSH_MSG_USERAUTH_SUCCESS");
+ agent.close();
+ return Result.Success;
+ } if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
+ log.info("Received SSH_MSG_USERAUTH_FAILURE");
+ if (keys.hasNext()) {
+ sendNextKey(keys.next().getFirst());
+ return Result.Continued;
+ } else {
+ agent.close();
+ return Result.Failure;
+ }
+ } else {
+ // TODO: check packets
+ log.info("Received unknown packet: {}", cmd);
+ return Result.Continued;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthKeyboardInteractive.java
new file mode 100644
index 0000000..cd9df71
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthKeyboardInteractive.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client.auth.deprecated;
+
+import java.io.IOException;
+
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.Buffer;
+
+import static org.apache.sshd.common.SshConstants.*;
+
+/**
+ * Userauth with keyboard-interactive method.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @author <a href="mailto:j.kapitza@schwarze-allianz.de">Jens Kapitza</a>
+ */
+public class UserAuthKeyboardInteractive extends AbstractUserAuth {
+
+ private final String password;
+
+ public UserAuthKeyboardInteractive(ClientSessionImpl session, String service, String password) {
+ super(session, service);
+ this.password = password;
+ }
+
+ public Result next(Buffer buffer) throws IOException {
+ if (buffer == null) {
+ log.info("Send SSH_MSG_USERAUTH_REQUEST for password");
+ buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
+ buffer.putString(session.getUsername());
+ buffer.putString(service);
+ buffer.putString("keyboard-interactive");
+ buffer.putString("");
+ buffer.putString("");
+ session.writePacket(buffer);
+ return Result.Continued;
+ } else {
+ byte cmd = buffer.getByte();
+ switch (cmd) {
+ case SSH_MSG_USERAUTH_INFO_REQUEST:
+ log.info("Received SSH_MSG_USERAUTH_INFO_REQUEST");
+ String name = buffer.getString();
+ String instruction = buffer.getString();
+ String language_tag = buffer.getString();
+ log.info("Received {} {} {}", new Object[]{name, instruction, language_tag});
+ int num = buffer.getInt();
+ String[] prompt = new String[num];
+ boolean[] echo = new boolean[num];
+ for (int i = 0; i < num; i++) {
+ prompt[i] = buffer.getString();
+ echo[i] = (buffer.getByte() != 0);
+ }
+ log.info("Promt: {}", prompt);
+ log.info("Echo: {}", echo);
+
+ String[] rep = null;
+ if (num == 0) {
+ rep = new String[0];
+ } else if (num == 1 && password != null && !echo[0] && prompt[0].toLowerCase().startsWith("password:")) {
+ rep = new String[] { password };
+ } else {
+ UserInteraction ui = session.getFactoryManager().getUserInteraction();
+ if (ui != null) {
+ String dest = session.getUsername() + "@" + session.getIoSession().getRemoteAddress().toString();
+ rep = ui.interactive(dest, name, instruction, prompt, echo);
+ }
+ }
+ if (rep == null) {
+ return Result.Failure;
+ }
+
+ buffer = session.createBuffer(SSH_MSG_USERAUTH_INFO_RESPONSE, 0);
+ buffer.putInt(rep.length);
+ for (String r : rep) {
+ buffer.putString(r);
+ }
+ session.writePacket(buffer);
+ return Result.Continued;
+ case SSH_MSG_USERAUTH_SUCCESS:
+ log.info("Received SSH_MSG_USERAUTH_SUCCESS");
+ return Result.Success;
+ case SSH_MSG_USERAUTH_FAILURE:
+ log.info("Received SSH_MSG_USERAUTH_FAILURE");
+ return Result.Failure;
+ default:
+ log.info("Received unknown packet {}", cmd);
+ return Result.Continued;
+ }
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthPassword.java
new file mode 100644
index 0000000..d2b5c9f
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthPassword.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client.auth.deprecated;
+
+import java.io.IOException;
+
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.Buffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPassword extends AbstractUserAuth {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ private final String password;
+
+ public UserAuthPassword(ClientSessionImpl session, String service, String password) {
+ super(session, service);
+ this.password = password;
+ }
+
+ public Result next(Buffer buffer) throws IOException {
+ if (buffer == null) {
+ log.info("Send SSH_MSG_USERAUTH_REQUEST for password");
+ buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
+ buffer.putString(session.getUsername());
+ buffer.putString(service);
+ buffer.putString("password");
+ buffer.putByte((byte) 0);
+ buffer.putString(password);
+ session.writePacket(buffer);
+ return Result.Continued;
+ } else {
+ byte cmd = buffer.getByte();
+ if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
+ log.info("Received SSH_MSG_USERAUTH_SUCCESS");
+ return Result.Success;
+ } if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
+ log.info("Received SSH_MSG_USERAUTH_FAILURE");
+ return Result.Failure;
+ } else {
+ log.info("Received unkown packet {}", cmd);
+ // TODO: check packets
+ return Result.Continued;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthPublicKey.java
new file mode 100644
index 0000000..9535066
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/deprecated/UserAuthPublicKey.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client.auth.deprecated;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.interfaces.RSAPublicKey;
+
+import org.apache.sshd.client.session.ClientSessionImpl;
+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.util.Buffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class UserAuthPublicKey extends AbstractUserAuth {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ private final KeyPair key;
+
+ public UserAuthPublicKey(ClientSessionImpl session, String service, KeyPair key) {
+ super(session, service);
+ this.key = key;
+ }
+
+ public Result next(Buffer buffer) throws IOException {
+ if (buffer == null) {
+ try {
+ log.info("Send SSH_MSG_USERAUTH_REQUEST for publickey");
+ buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
+ int pos1 = buffer.wpos() - 1;
+ buffer.putString(session.getUsername());
+ buffer.putString(service);
+ buffer.putString("publickey");
+ buffer.putByte((byte) 1);
+ buffer.putString((key.getPublic() instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
+ int pos2 = buffer.wpos();
+ buffer.putPublicKey(key.getPublic());
+
+ // TODO: support elliptic keys
+ Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), (key.getPublic() instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
+ verif.init(key.getPublic(), key.getPrivate());
+
+ Buffer bs = new Buffer();
+ bs.putString(session.getKex().getH());
+ bs.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+ bs.putString(session.getUsername());
+ bs.putString(service);
+ bs.putString("publickey");
+ bs.putByte((byte) 1);
+ bs.putString((key.getPublic() instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
+ bs.putPublicKey(key.getPublic());
+ verif.update(bs.array(), bs.rpos(), bs.available());
+
+ bs = new Buffer();
+ bs.putString((key.getPublic() instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS);
+ bs.putBytes(verif.sign());
+ buffer.putBytes(bs.array(), bs.rpos(), bs.available());
+
+ session.writePacket(buffer);
+ return Result.Continued;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw (IOException) new IOException("Error performing public key authentication").initCause(e);
+ }
+ } else {
+ byte cmd = buffer.getByte();
+ if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
+ log.info("Received SSH_MSG_USERAUTH_SUCCESS");
+ return Result.Success;
+ } if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
+ log.info("Received SSH_MSG_USERAUTH_FAILURE");
+ return Result.Failure;
+ } else {
+ log.info("Received unknown packet {}", cmd);
+ // TODO: check packets
+ return Result.Continued;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/future/AuthFuture.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/future/AuthFuture.java b/sshd-core/src/main/java/org/apache/sshd/client/future/AuthFuture.java
index 6b8bdb8..081474a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/future/AuthFuture.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/future/AuthFuture.java
@@ -18,6 +18,7 @@
*/
package org.apache.sshd.client.future;
+import org.apache.sshd.common.SshException;
import org.apache.sshd.common.future.SshFuture;
/**
@@ -28,6 +29,13 @@ import org.apache.sshd.common.future.SshFuture;
public interface AuthFuture extends SshFuture<AuthFuture> {
/**
+ * Wait and verify that the authentication succeeded.
+ *
+ * @throws SshException if the authentication failed for any reason
+ */
+ void verify() throws SshException;
+
+ /**
* Returns the cause of the connection failure.
*
* @return <tt>null</tt> if the connect operation is not finished yet,
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultAuthFuture.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultAuthFuture.java b/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultAuthFuture.java
index 528bed3..176eadc 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultAuthFuture.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultAuthFuture.java
@@ -18,6 +18,7 @@
*/
package org.apache.sshd.client.future;
+import org.apache.sshd.common.SshException;
import org.apache.sshd.common.future.DefaultSshFuture;
@@ -32,6 +33,18 @@ public class DefaultAuthFuture extends DefaultSshFuture<AuthFuture> implements A
super(lock);
}
+ public void verify() throws SshException {
+ try {
+ await();
+ }
+ catch (InterruptedException e) {
+ throw new SshException("Authentication interrupted", e);
+ }
+ if (!isSuccess()) {
+ throw new SshException("Authentication failed", getException());
+ }
+ }
+
public Throwable getException() {
Object v = getValue();
if (v instanceof Throwable) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/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 720ce4b..bed1e36 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
@@ -21,6 +21,7 @@ package org.apache.sshd.client.session;
import java.io.IOException;
import java.net.SocketAddress;
import java.security.KeyPair;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -31,11 +32,11 @@ import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.ScpClient;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.SftpClient;
-import org.apache.sshd.client.UserAuth;
-import org.apache.sshd.client.auth.UserAuthAgent;
-import org.apache.sshd.client.auth.UserAuthKeyboardInteractive;
-import org.apache.sshd.client.auth.UserAuthPassword;
-import org.apache.sshd.client.auth.UserAuthPublicKey;
+import org.apache.sshd.client.auth.deprecated.UserAuth;
+import org.apache.sshd.client.auth.deprecated.UserAuthAgent;
+import org.apache.sshd.client.auth.deprecated.UserAuthKeyboardInteractive;
+import org.apache.sshd.client.auth.deprecated.UserAuthPassword;
+import org.apache.sshd.client.auth.deprecated.UserAuthPublicKey;
import org.apache.sshd.client.channel.ChannelDirectTcpip;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.channel.ChannelShell;
@@ -105,23 +106,43 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
return (ClientFactoryManager) factoryManager;
}
+ private final List<Object> identities = new ArrayList<Object>();
+
+ public void addPasswordIdentity(String password) {
+ identities.add(password);
+ }
+
+ public void addPublicKeyIdentity(KeyPair key) {
+ identities.add(key);
+ }
+
+ public AuthFuture auth() throws IOException {
+ if (username == null) {
+ throw new IllegalStateException("No username specified when the session was created");
+ }
+ synchronized (lock) {
+ return authFuture = getUserAuthService().auth(identities, nextServiceName());
+ }
+ }
+
public AuthFuture authAgent(String user) throws IOException {
- return tryAuth(new UserAuthAgent(this, nextServiceName(), user));
+ return tryAuth(user, new UserAuthAgent(this, nextServiceName()));
}
public AuthFuture authPassword(String user, String password) throws IOException {
- return tryAuth(new UserAuthPassword(this, nextServiceName(), user, password));
+ return tryAuth(user, new UserAuthPassword(this, nextServiceName(), password));
}
public AuthFuture authInteractive(String user, String password) throws IOException {
- return tryAuth(new UserAuthKeyboardInteractive(this, nextServiceName(), user, password));
+ return tryAuth(user, new UserAuthKeyboardInteractive(this, nextServiceName(), password));
}
public AuthFuture authPublicKey(String user, KeyPair key) throws IOException {
- return tryAuth(new UserAuthPublicKey(this, nextServiceName(), user, key));
+ return tryAuth(user, new UserAuthPublicKey(this, nextServiceName(), key));
}
- private AuthFuture tryAuth(UserAuth auth) throws IOException {
+ private AuthFuture tryAuth(String user, UserAuth auth) throws IOException {
+ this.username = user;
synchronized (lock) {
return authFuture = getUserAuthService().auth(auth);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/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 9612b9b..d5c0b27 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,16 +19,13 @@
package org.apache.sshd.client.session;
import java.io.IOException;
+import java.util.List;
-import org.apache.sshd.client.UserAuth;
-import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.auth.deprecated.UserAuth;
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.ServiceFactory;
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;
@@ -56,28 +53,16 @@ public class ClientUserAuthService 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;
+ protected ClientUserAuthServiceNew delegateNew;
+ protected ClientUserAuthServiceOld delegateOld;
+ protected boolean started;
public ClientUserAuthService(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() {
@@ -85,117 +70,58 @@ public class ClientUserAuthService implements Service {
}
public void start() {
- synchronized (lock) {
- log.debug("accepted");
- // kick start the authentication process by failing the pending auth.
- this.authFuture.setAuthed(false);
+ if (delegateNew != null) {
+ delegateNew.start();
+ } else if (delegateOld != null) {
+ delegateOld.start();
}
+ started = true;
}
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);
- }
+ if (delegateNew != null) {
+ delegateNew.process(cmd, buffer);
+ } else if (delegateOld != null) {
+ delegateOld.process(cmd, buffer);
} else {
- buffer.rpos(buffer.rpos() - 1);
- processUserAuth(buffer);
+ throw new IllegalStateException();
}
}
- /**
- * 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?");
+ public CloseFuture close(boolean immediately) {
+ if (delegateNew != null) {
+ return delegateNew.close(immediately);
+ } else if (delegateOld != null) {
+ return delegateOld.close(immediately);
+ } else {
+ CloseFuture future = new DefaultCloseFuture(session.getLock());
+ future.setClosed();
+ return future;
}
- // 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 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(userAuth.getUsername());
- 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 AuthFuture auth(UserAuth userAuth) throws IOException {
+ if (delegateNew != null) {
+ throw new IllegalStateException();
}
- }
-
- public CloseFuture close(boolean immediately) {
- if (!authFuture.isDone()) {
- authFuture.setException(new SshException("Session is closed"));
+ if (delegateOld == null) {
+ delegateOld = new ClientUserAuthServiceOld(session);
+ if (started) {
+ delegateOld.start();
+ }
}
- CloseFuture future = new DefaultCloseFuture(lock);
- future.setClosed();
- return future;
+ return delegateOld.auth(userAuth);
}
- public AuthFuture auth(UserAuth userAuth) throws IOException {
- log.debug("Trying authentication with {}", userAuth);
- synchronized (lock) {
- if (readyForAuth(userAuth)) {
- processUserAuth(null);
- }
- return authFuture;
+ public AuthFuture auth(List<Object> identities, String service) throws IOException {
+ if (delegateOld != null || delegateNew != null) {
+ throw new IllegalStateException();
+ }
+ delegateNew = new ClientUserAuthServiceNew(session);
+ if (started) {
+ delegateNew.start();
}
+ return delegateNew.auth(identities, service);
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0824b93b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthServiceNew.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthServiceNew.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthServiceNew.java
new file mode 100644
index 0000000..96d8208
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthServiceNew.java
@@ -0,0 +1,227 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.sshd.client.ClientFactoryManager;
+import org.apache.sshd.client.UserAuth;
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.auth.UserAuthKeyboardInteractive;
+import org.apache.sshd.client.auth.UserAuthPassword;
+import org.apache.sshd.client.auth.UserAuthPublicKey;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.future.DefaultAuthFuture;
+import org.apache.sshd.common.NamedFactory;
+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;
+
+import static org.apache.sshd.common.util.KeyUtils.getKeyType;
+
+/**
+ * Client side <code>ssh-auth</code> service.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class ClientUserAuthServiceNew implements Service {
+
+ /** Our logger */
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * 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;
+
+ protected final ClientSessionImpl session;
+
+ private List<Object> identities;
+ private String service;
+
+ List<NamedFactory<UserAuth>> authFactories;
+ List<String> clientMethods;
+ List<String> serverMethods;
+ UserAuth userAuth;
+
+ public ClientUserAuthServiceNew(Session s) {
+ if (!(s instanceof ClientSessionImpl)) {
+ throw new IllegalStateException("Client side service used on server side");
+ }
+ session = (ClientSessionImpl) s;
+ authFuture = new DefaultAuthFuture(session.getLock());
+ authFactories = session.getFactoryManager().getUserAuthFactories();
+ clientMethods = new ArrayList<String>();
+ String prefs = session.getFactoryManager().getProperties().get(ClientFactoryManager.PREFERRED_AUTHS);
+ if (prefs != null) {
+ for (String pref : prefs.split(",")) {
+ if (NamedFactory.Utils.get(authFactories, pref) != null) {
+ clientMethods.add(pref);
+ }
+ }
+ } else {
+ for (NamedFactory<UserAuth> factory : authFactories) {
+ clientMethods.add(factory.getName());
+ }
+ }
+ }
+
+ public ClientSessionImpl getSession() {
+ return session;
+ }
+
+ public void start() {
+ }
+
+ public AuthFuture auth(List<Object> identities, String service) throws IOException {
+ log.debug("Start authentication");
+ this.identities = new ArrayList<Object>(identities);
+ this.service = service;
+
+ log.debug("Send SSH_MSG_USERAUTH_REQUEST for none");
+ Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, 0);
+ buffer.putString(session.getUsername());
+ buffer.putString(service);
+ buffer.putString("none");
+ session.writePacket(buffer);
+
+ return authFuture;
+ }
+
+ 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);
+ }
+ }
+
+ int currentMethod;
+
+ /**
+ * execute one step in user authentication.
+ * @param buffer
+ * @throws java.io.IOException
+ */
+ private void processUserAuth(Buffer buffer) throws Exception {
+ byte cmd = buffer.getByte();
+ if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
+ log.info("Received SSH_MSG_USERAUTH_SUCCESS");
+ log.debug("Succeeded with {}", userAuth);
+ if (userAuth != null) {
+ userAuth.destroy();
+ userAuth = null;
+ }
+ session.setAuthenticated();
+ session.switchToNextService();
+ // Will wake up anyone sitting in waitFor
+ authFuture.setAuthed(true);
+ return;
+ }
+ if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
+ log.info("Received SSH_MSG_USERAUTH_FAILURE");
+ String mths = buffer.getString();
+ boolean partial = buffer.getBoolean();
+ if (partial || serverMethods == null) {
+ serverMethods = Arrays.asList(mths.split(","));
+ if (log.isDebugEnabled()) {
+ StringBuilder sb = new StringBuilder("Authentications that can continue: ");
+ for (int i = 0; i < serverMethods.size(); i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(serverMethods.get(i));
+ }
+ log.debug(sb.toString());
+ }
+ if (userAuth != null) {
+ userAuth.destroy();
+ userAuth = null;
+ }
+ }
+ tryNext();
+ return;
+ }
+ if (userAuth == null) {
+ throw new IllegalStateException("Received unknown packet");
+ }
+ buffer.rpos(buffer.rpos() - 1);
+ if (!userAuth.process(buffer)) {
+ tryNext();
+ }
+ }
+
+ private void tryNext() throws Exception {
+ // Loop until we find something to try
+ while (true) {
+ if (userAuth == null) {
+ currentMethod = 0;
+ } else if (!userAuth.process(null)) {
+ userAuth.destroy();
+ currentMethod++;
+ } else {
+ return;
+ }
+ while (currentMethod < clientMethods.size() && !serverMethods.contains(clientMethods.get(currentMethod))) {
+ currentMethod++;
+ }
+ if (currentMethod >= clientMethods.size()) {
+ // Failure
+ authFuture.setAuthed(false);
+ return;
+ }
+ String method = clientMethods.get(currentMethod);
+ userAuth = NamedFactory.Utils.create(authFactories, method);
+ assert userAuth != null;
+ userAuth.init(session, service, identities);
+ }
+ }
+
+ public CloseFuture close(boolean immediately) {
+ if (!authFuture.isDone()) {
+ authFuture.setException(new SshException("Session is closed"));
+ }
+ CloseFuture future = new DefaultCloseFuture(session.getLock());
+ future.setClosed();
+ return future;
+ }
+
+}