You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/12/09 11:07:04 UTC
[1/6] mina-sshd git commit: [SSHD-474] Null pointer exception when
connecting with latest Dropbear's dbclient
Repository: mina-sshd
Updated Branches:
refs/heads/master 28faad412 -> 0371baefc
[SSHD-474] Null pointer exception when connecting with latest Dropbear's dbclient
* Alleviate the problem - there is now a data stream corruption...
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/56b5f0e8
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/56b5f0e8
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/56b5f0e8
Branch: refs/heads/master
Commit: 56b5f0e888d5983c7dc0b0b0776d6cbd2be97c64
Parents: 28faad4
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Wed Dec 9 11:34:36 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Wed Dec 9 11:34:36 2015 +0200
----------------------------------------------------------------------
.../org/apache/sshd/client/kex/DHGClient.java | 3 +-
.../org/apache/sshd/client/kex/DHGEXClient.java | 3 +-
.../org/apache/sshd/common/kex/KeyExchange.java | 5 +-
.../sshd/common/session/AbstractSession.java | 87 ++++++++++++++++----
.../org/apache/sshd/server/kex/DHGEXServer.java | 3 +-
.../org/apache/sshd/server/kex/DHGServer.java | 3 +-
6 files changed, 76 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/56b5f0e8/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
index 430c296..c676c35 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
@@ -98,8 +98,7 @@ public class DHGClient extends AbstractDHClientKeyExchange {
}
@Override
- public boolean next(Buffer buffer) throws Exception {
- int cmd = buffer.getUByte();
+ public boolean next(int cmd, Buffer buffer) throws Exception {
Session session = getSession();
if (log.isDebugEnabled()) {
log.debug("next({})[{}] process command={}", this, session, KeyExchange.Utils.getSimpleKexOpcodeName(cmd));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/56b5f0e8/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
index dca86aa..c521749 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
@@ -102,8 +102,7 @@ public class DHGEXClient extends AbstractDHClientKeyExchange {
}
@Override
- public boolean next(Buffer buffer) throws Exception {
- int cmd = buffer.getUByte();
+ public boolean next(int cmd, Buffer buffer) throws Exception {
Session session = getSession();
if (log.isDebugEnabled()) {
log.debug("next({})[{}] process command={}", this, session, KeyExchange.Utils.getGroupKexOpcodeName(cmd));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/56b5f0e8/sshd-core/src/main/java/org/apache/sshd/common/kex/KeyExchange.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/KeyExchange.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/KeyExchange.java
index 24fcd57..a3364a9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/kex/KeyExchange.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/KeyExchange.java
@@ -51,11 +51,12 @@ public interface KeyExchange extends NamedResource {
/**
* Process the next packet
*
- * @param buffer the packet
+ * @param cmd the command
+ * @param buffer the packet contents positioned after the command
* @return a boolean indicating if the processing is complete or if more packets are to be received
* @throws Exception if an error occurs
*/
- boolean next(Buffer buffer) throws Exception;
+ boolean next(int cmd, Buffer buffer) throws Exception;
/**
* The message digest used by this key exchange algorithm.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/56b5f0e8/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 1347245..74d275f 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
@@ -144,6 +144,7 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
protected byte[] i_c; // the payload of the client's SSH_MSG_KEXINIT
protected byte[] i_s; // the payload of the factoryManager's SSH_MSG_KEXINIT
protected KeyExchange kex;
+ protected Boolean firstKexPacketFollows;
protected final AtomicReference<KexState> kexState = new AtomicReference<>(KexState.UNKNOWN);
protected final AtomicReference<DefaultKeyExchangeFuture> kexFutureHolder = new AtomicReference<>(null);
@@ -416,22 +417,18 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
}
switch (cmd) {
- case SshConstants.SSH_MSG_DISCONNECT: {
+ case SshConstants.SSH_MSG_DISCONNECT:
handleDisconnect(buffer);
break;
- }
- case SshConstants.SSH_MSG_IGNORE: {
+ case SshConstants.SSH_MSG_IGNORE:
handleIgnore(buffer);
break;
- }
- case SshConstants.SSH_MSG_UNIMPLEMENTED: {
+ case SshConstants.SSH_MSG_UNIMPLEMENTED:
handleUnimplented(buffer);
break;
- }
- case SshConstants.SSH_MSG_DEBUG: {
+ case SshConstants.SSH_MSG_DEBUG:
handleDebug(buffer);
break;
- }
case SshConstants.SSH_MSG_SERVICE_REQUEST:
handleServiceRequest(buffer);
break;
@@ -446,13 +443,17 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
break;
default:
if ((cmd >= SshConstants.SSH_MSG_KEX_FIRST) && (cmd <= SshConstants.SSH_MSG_KEX_LAST)) {
- validateKexState(cmd, KexState.RUN);
- buffer.rpos(buffer.rpos() - 1);
- if (kex.next(buffer)) {
- checkKeys();
- sendNewKeys();
- kexState.set(KexState.KEYS);
+ if (firstKexPacketFollows != null) {
+ try {
+ if (!handleFirstKexPacketFollows(cmd, buffer, firstKexPacketFollows.booleanValue())) {
+ break;
+ }
+ } finally {
+ firstKexPacketFollows = null; // avoid re-checking
+ }
}
+
+ handleKexMessage(cmd, buffer);
} else if (currentService != null) {
currentService.process(cmd, buffer);
resetIdleTimeout();
@@ -464,6 +465,56 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
checkRekey();
}
+ protected boolean handleFirstKexPacketFollows(int cmd, Buffer buffer, boolean followFlag) {
+ if (!followFlag) {
+ return true; // if 1st KEX packet does not follow then process the command
+ }
+
+ /*
+ * According to RFC4253 section 7.1:
+ *
+ * If the other party's guess was wrong, and this field was TRUE,
+ * the next packet MUST be silently ignored
+ */
+ for (KexProposalOption option : new KexProposalOption[]{KexProposalOption.ALGORITHMS, KexProposalOption.SERVERKEYS}) {
+ Pair<String, String> result = comparePreferredKexProposalOption(option);
+ if (result != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("handleKexMessage({})[{}] 1st follow KEX packet {} option mismatch: client={}, server={}",
+ this, SshConstants.getCommandMessageName(cmd), option, result.getFirst(), result.getSecond());
+ }
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected Pair<String, String> comparePreferredKexProposalOption(KexProposalOption option) {
+ String[] clientPreferences = GenericUtils.split(clientProposal.get(option), ',');
+ String clientValue = clientPreferences[0];
+ String[] serverPreferences = GenericUtils.split(serverProposal.get(option), ',');
+ String serverValue = serverPreferences[0];
+ return clientValue.equals(serverValue) ? null : new Pair<>(clientValue, serverValue);
+ }
+
+ protected void handleKexMessage(int cmd, Buffer buffer) throws Exception {
+ validateKexState(cmd, KexState.RUN);
+
+ if (kex.next(cmd, buffer)) {
+ if (log.isDebugEnabled()) {
+ log.debug("handleKexMessage({})[{}] KEX processing complete after cmd={}", this, kex.getName(), cmd);
+ }
+ checkKeys();
+ sendNewKeys();
+ kexState.set(KexState.KEYS);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("handleKexMessage({})[{}] more KEX packets expected after cmd={}", this, kex.getName(), cmd);
+ }
+ }
+ }
+
protected void handleIgnore(Buffer buffer) throws Exception {
if (log.isDebugEnabled()) {
log.debug("handleIgnore({}) SSH_MSG_IGNORE", this);
@@ -551,7 +602,6 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
"Unknown negotiated KEX algorithm: %s",
kexAlgorithm);
kex.init(this, serverVersion.getBytes(StandardCharsets.UTF_8), clientVersion.getBytes(StandardCharsets.UTF_8), i_s, i_c);
-
sendSessionEvent(SessionListener.Event.KexCompleted);
}
@@ -954,7 +1004,7 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
assert decoderBuffer.rpos() == 4;
int macSize = inMac != null ? inMac.getBlockSize() : 0;
// Check if the packet has been fully received
- if (decoderBuffer.available() >= decoderLength + macSize) {
+ if (decoderBuffer.available() >= (decoderLength + macSize)) {
byte[] data = decoderBuffer.array();
// Decrypt the remaining of the packet
if (inCipher != null) {
@@ -1000,7 +1050,7 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
}
if (log.isTraceEnabled()) {
- log.trace("decode({}) Received packet #{}: {}", this, Long.valueOf(seqi), buf.printHex());
+ log.trace("decode({}) Received packet #{}: {}", this, seqi, buf.printHex());
}
// Update stats
@@ -1201,7 +1251,7 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
size += readLen;
}
- boolean firstKexPacketFollows = buffer.getBoolean();
+ firstKexPacketFollows = buffer.getBoolean();
if (log.isTraceEnabled()) {
log.trace("receiveKexInit(" + toString() + ") first kex packet follows: " + firstKexPacketFollows);
}
@@ -1362,6 +1412,7 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
inBlocksCount.set(0L);
outBlocksCount.set(0L);
lastKeyTimeValue.set(System.currentTimeMillis());
+ firstKexPacketFollows = null;
}
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/56b5f0e8/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
index 4694de4..b427c08 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
@@ -101,8 +101,7 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
}
@Override
- public boolean next(Buffer buffer) throws Exception {
- int cmd = buffer.getUByte();
+ public boolean next(int cmd, Buffer buffer) throws Exception {
ServerSession session = getServerSession();
if (log.isDebugEnabled()) {
log.debug("next({})[{}] process command={}", this, session, KeyExchange.Utils.getGroupKexOpcodeName(cmd));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/56b5f0e8/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
index 8a9704a..e6a9ef2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
@@ -84,8 +84,7 @@ public class DHGServer extends AbstractDHServerKeyExchange {
}
@Override
- public boolean next(Buffer buffer) throws Exception {
- int cmd = buffer.getUByte();
+ public boolean next(int cmd, Buffer buffer) throws Exception {
ServerSession session = getServerSession();
if (log.isDebugEnabled()) {
log.debug("next({})[{}] process command={}", this, session, KeyExchange.Utils.getSimpleKexOpcodeName(cmd));
[2/6] mina-sshd git commit: Specify
SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE as the disconnect reason if failed to
verify server key
Posted by lg...@apache.org.
Specify SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE as the disconnect reason if failed to verify server key
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/2a3d0fda
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/2a3d0fda
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/2a3d0fda
Branch: refs/heads/master
Commit: 2a3d0fda13008a875496772c0bb06f97d383861c
Parents: 56b5f0e
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Wed Dec 9 11:35:17 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Wed Dec 9 11:35:17 2015 +0200
----------------------------------------------------------------------
.../java/org/apache/sshd/client/session/ClientSessionImpl.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/2a3d0fda/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 103925f..d10e8cd 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
@@ -364,7 +364,7 @@ public class ClientSessionImpl extends AbstractClientSession {
SocketAddress remoteAddress = ioSession.getRemoteAddress();
if (!serverKeyVerifier.verifyServerKey(this, remoteAddress, kex.getServerKey())) {
- throw new SshException("Server key did not validate");
+ throw new SshException(SshConstants.SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, "Server key did not validate");
}
}
[4/6] mina-sshd git commit: Fixed keys re-exchange request logic in
case of automatic re-exchange due to thresholds
Posted by lg...@apache.org.
Fixed keys re-exchange request logic in case of automatic re-exchange due to thresholds
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/d99d4806
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/d99d4806
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/d99d4806
Branch: refs/heads/master
Commit: d99d4806e00a68a5dcbe5d634fe8b3113c360360
Parents: 05f5d36
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Wed Dec 9 12:00:06 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Wed Dec 9 12:00:06 2015 +0200
----------------------------------------------------------------------
.../sshd/common/session/AbstractSession.java | 85 +++++++++++++-------
.../org/apache/sshd/common/session/Session.java | 4 +-
.../java/org/apache/sshd/KeyReExchangeTest.java | 36 +++++++++
.../java/org/apache/sshd/server/ServerTest.java | 3 +-
.../test/OutputCountTrackingOutputStream.java | 4 +-
5 files changed, 96 insertions(+), 36 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d99d4806/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 74d275f..c7fddef 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
@@ -424,7 +424,7 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
handleIgnore(buffer);
break;
case SshConstants.SSH_MSG_UNIMPLEMENTED:
- handleUnimplented(buffer);
+ handleUnimplemented(buffer);
break;
case SshConstants.SSH_MSG_DEBUG:
handleDebug(buffer);
@@ -439,7 +439,7 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
handleKexInit(buffer);
break;
case SshConstants.SSH_MSG_NEWKEYS:
- handleNewKeys(cmd);
+ handleNewKeys(cmd, buffer);
break;
default:
if ((cmd >= SshConstants.SSH_MSG_KEX_FIRST) && (cmd <= SshConstants.SSH_MSG_KEX_LAST)) {
@@ -521,17 +521,21 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
}
}
- protected void handleUnimplented(Buffer buffer) throws Exception {
- int seqNo = buffer.getInt();
+ protected void handleUnimplemented(Buffer buffer) throws Exception {
+ handleUnimplemented(buffer.getInt(), buffer);
+ }
+
+ protected void handleUnimplemented(int seqNo, Buffer buffer) throws Exception {
if (log.isDebugEnabled()) {
log.debug("handleUnimplented({}) SSH_MSG_UNIMPLEMENTED #{}", this, seqNo);
}
}
protected void handleDebug(Buffer buffer) throws Exception {
- boolean display = buffer.getBoolean();
- String msg = buffer.getString();
- String lang = buffer.getString();
+ handleDebug(buffer.getBoolean(), buffer.getString(), buffer.getString(), buffer);
+ }
+
+ protected void handleDebug(boolean display, String msg, String lang, Buffer buffer) throws Exception {
if (log.isDebugEnabled()) {
log.debug("handleDebug({}) SSH_MSG_DEBUG (display={}) [lang={}] '{}'",
this, display, lang, msg);
@@ -539,18 +543,23 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
}
protected void handleDisconnect(Buffer buffer) throws Exception {
- int code = buffer.getInt();
- String msg = buffer.getString();
- String lang = buffer.getString();
+ handleDisconnect(buffer.getInt(), buffer.getString(), buffer.getString(), buffer);
+ }
+
+ protected void handleDisconnect(int code, String msg, String lang, Buffer buffer) throws Exception {
if (log.isDebugEnabled()) {
log.debug("handleDisconnect({}) SSH_MSG_DISCONNECT reason={}, [lang={}] msg={}",
this, SshConstants.getDisconnectReasonName(code), lang, msg);
}
+
close(true);
}
- protected void handleServiceRequest(Buffer buffer) throws IOException {
- String serviceName = buffer.getString();
+ protected void handleServiceRequest(Buffer buffer) throws Exception {
+ handleServiceRequest(buffer.getString(), buffer);
+ }
+
+ protected void handleServiceRequest(String serviceName, Buffer buffer) throws Exception {
if (log.isDebugEnabled()) {
log.debug("handleServiceRequest({}) SSH_MSG_SERVICE_REQUEST '{}'", this, serviceName);
}
@@ -569,16 +578,21 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
disconnect(SshConstants.SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE, "Bad service request: " + serviceName);
return;
}
+
if (log.isDebugEnabled()) {
log.debug("handleServiceRequest({}) Accepted service {}", this, serviceName);
}
+
Buffer response = prepareBuffer(SshConstants.SSH_MSG_SERVICE_ACCEPT, BufferUtils.clear(buffer));
response.putString(serviceName);
writePacket(response);
}
- protected void handleServiceAccept(Buffer buffer) throws IOException {
- String serviceName = buffer.getString();
+ protected void handleServiceAccept(Buffer buffer) throws Exception {
+ handleServiceAccept(buffer.getString(), buffer);
+ }
+
+ protected void handleServiceAccept(String serviceName, Buffer buffer) throws Exception {
if (log.isDebugEnabled()) {
log.debug("handleServiceAccept({}) SSH_MSG_SERVICE_ACCEPT service={}", this, serviceName);
}
@@ -605,7 +619,7 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
sendSessionEvent(SessionListener.Event.KexCompleted);
}
- protected void handleNewKeys(int cmd) throws Exception {
+ protected void handleNewKeys(int cmd, Buffer buffer) throws Exception {
if (log.isDebugEnabled()) {
log.debug("handleNewKeys({}) SSH_MSG_NEWKEYS command={}", this, SshConstants.getCommandMessageName(cmd));
}
@@ -1692,27 +1706,36 @@ public abstract class AbstractSession extends AbstractKexFactoryManager implemen
@Override
public KeyExchangeFuture reExchangeKeys() throws IOException {
- if (kexState.compareAndSet(KexState.DONE, KexState.INIT)) {
- log.info("reExchangeKeys({}) Initiating key re-exchange", this);
- sendKexInit();
-
- DefaultKeyExchangeFuture kexFuture = kexFutureHolder.getAndSet(new DefaultKeyExchangeFuture(null));
- if (kexFuture != null) {
- synchronized (kexFuture) {
- Object value = kexFuture.getValue();
- if (value == null) {
- kexFuture.setValue(new SshException("New KEX started while previous one still ongoing"));
- }
- }
- }
- }
-
+ requestNewKeysExchange();
return ValidateUtils.checkNotNull(kexFutureHolder.get(), "No current KEX future on state=%s", kexState.get());
}
protected void checkRekey() throws IOException {
if (isRekeyRequired()) {
- reExchangeKeys();
+ requestNewKeysExchange();
+ }
+ }
+
+ protected void requestNewKeysExchange() throws IOException {
+ if (!kexState.compareAndSet(KexState.DONE, KexState.INIT)) {
+ if (log.isDebugEnabled()) {
+ log.debug("requestNewKeysExchange({}) KEX state not DONE: {}", this, kexState.get());
+ }
+
+ return;
+ }
+
+ log.info("requestNewKeysExchange({}) Initiating key re-exchange", this);
+ sendKexInit();
+
+ DefaultKeyExchangeFuture kexFuture = kexFutureHolder.getAndSet(new DefaultKeyExchangeFuture(null));
+ if (kexFuture != null) {
+ synchronized (kexFuture) {
+ Object value = kexFuture.getValue();
+ if (value == null) {
+ kexFuture.setValue(new SshException("New KEX started while previous one still ongoing"));
+ }
+ }
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d99d4806/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java b/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java
index db9de87..c31d589 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java
@@ -226,8 +226,8 @@ public interface Session
/**
* Initiate a new key exchange.
*
- * @return An {@link KeyExchangeFuture} for awaiting the completion of the exchange
- * @throws IOException If failed to negotiate keys
+ * @return A {@link KeyExchangeFuture} for awaiting the completion of the exchange
+ * @throws IOException If failed to request keys re-negotiation
*/
KeyExchangeFuture reExchangeKeys() throws IOException;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d99d4806/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
index 34d1a40..242e3b4 100644
--- a/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
@@ -264,17 +264,26 @@ public class KeyReExchangeTest extends BaseTestSupport {
InputStream inPipe = new PipedInputStream(pipedIn);
OutputStream teeOut = new TeeOutputStream(sent, pipedIn);
ByteArrayOutputStream out = new ByteArrayOutputStream() {
+ private long writeCount = 0L;
+
@Override
public void write(int b) {
super.write(b);
+ updateWriteCount(1L);
pipedCount.release(1);
}
@Override
public void write(byte[] b, int off, int len) {
super.write(b, off, len);
+ updateWriteCount(len);
pipedCount.release(len);
}
+
+ private void updateWriteCount(long delta) {
+ writeCount += delta;
+ outputDebugMessage("OUT write count=%d", writeCount);
+ }
};
ByteArrayOutputStream err = new ByteArrayOutputStream()) {
@@ -333,17 +342,26 @@ public class KeyReExchangeTest extends BaseTestSupport {
try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession();
ByteArrayOutputStream sent = new ByteArrayOutputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream() {
+ private long writeCount = 0L;
+
@Override
public void write(int b) {
super.write(b);
+ updateWriteCount(1L);
pipedCount.release(1);
}
@Override
public void write(byte[] b, int off, int len) {
super.write(b, off, len);
+ updateWriteCount(len);
pipedCount.release(len);
}
+
+ private void updateWriteCount(long delta) {
+ writeCount += delta;
+ outputDebugMessage("OUT write count=%d", writeCount);
+ }
}) {
session.addPasswordIdentity(getCurrentTestName());
session.auth().verify(5L, TimeUnit.SECONDS);
@@ -436,17 +454,26 @@ public class KeyReExchangeTest extends BaseTestSupport {
try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession();
ByteArrayOutputStream sent = new ByteArrayOutputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream() {
+ private long writeCount = 0L;
+
@Override
public void write(int b) {
super.write(b);
+ updateWriteCount(1L);
pipedCount.release(1);
}
@Override
public void write(byte[] b, int off, int len) {
super.write(b, off, len);
+ updateWriteCount(len);
pipedCount.release(len);
}
+
+ private void updateWriteCount(long delta) {
+ writeCount += delta;
+ outputDebugMessage("OUT write count=%d", writeCount);
+ }
}) {
session.addPasswordIdentity(getCurrentTestName());
session.auth().verify(5L, TimeUnit.SECONDS);
@@ -557,17 +584,26 @@ public class KeyReExchangeTest extends BaseTestSupport {
try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession();
ByteArrayOutputStream sent = new ByteArrayOutputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream() {
+ private long writeCount = 0L;
+
@Override
public void write(int b) {
super.write(b);
+ updateWriteCount(1L);
pipedCount.release(1);
}
@Override
public void write(byte[] b, int off, int len) {
super.write(b, off, len);
+ updateWriteCount(len);
pipedCount.release(len);
}
+
+ private void updateWriteCount(long delta) {
+ writeCount += delta;
+ outputDebugMessage("OUT write count=%d", writeCount);
+ }
}) {
session.addPasswordIdentity(getCurrentTestName());
session.auth().verify(5L, TimeUnit.SECONDS);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d99d4806/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
index e45c51c..8bf16db 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
@@ -167,7 +167,8 @@ public class ServerTest extends BaseTestSupport {
assertFalse("Authentication unexpectedly successful", authFuture.isSuccess());
} while (authFuture.getException() == null);
- assertNotNull("Missing auth future exception", authFuture.getException());
+ Throwable t = authFuture.getException();
+ assertNotNull("Missing auth future exception", t);
assertTrue("Number trials (" + nbTrials + ") below min.=" + MAX_AUTH_REQUESTS, nbTrials > MAX_AUTH_REQUESTS);
} finally {
client.stop();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d99d4806/sshd-core/src/test/java/org/apache/sshd/util/test/OutputCountTrackingOutputStream.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/test/OutputCountTrackingOutputStream.java b/sshd-core/src/test/java/org/apache/sshd/util/test/OutputCountTrackingOutputStream.java
index 0cb6ec4..b4eb84c 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/test/OutputCountTrackingOutputStream.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/test/OutputCountTrackingOutputStream.java
@@ -35,13 +35,13 @@ public class OutputCountTrackingOutputStream extends FilterOutputStream {
@Override
public void write(int b) throws IOException {
- super.write(b);
+ out.write(b);
updateWriteCount(1L);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
- super.write(b, off, len);
+ out.write(b, off, len); // don't call super since it calls the single 'write'
updateWriteCount(len);
}
[3/6] mina-sshd git commit: Send
SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE if failed to create requested service
Posted by lg...@apache.org.
Send SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE if failed to create requested service
* As sanctioned by RFC4253 section 10
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/05f5d36c
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/05f5d36c
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/05f5d36c
Branch: refs/heads/master
Commit: 05f5d36c073a3b0ec789ef4a77835b75fc0d6455
Parents: 2a3d0fd
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Wed Dec 9 11:57:04 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Wed Dec 9 11:57:04 2015 +0200
----------------------------------------------------------------------
.../apache/sshd/server/session/ServerSessionImpl.java | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/05f5d36c/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSessionImpl.java
index f506924..32ae420 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSessionImpl.java
@@ -66,7 +66,19 @@ public class ServerSessionImpl extends AbstractServerSession {
@Override
public void startService(String name) throws Exception {
- currentService = ServiceFactory.Utils.create(getFactoryManager().getServiceFactories(), name, this);
+ currentService = ServiceFactory.Utils.create(
+ getFactoryManager().getServiceFactories(),
+ ValidateUtils.checkNotNullAndNotEmpty(name, "No service name"),
+ this);
+ /*
+ * According to RFC4253:
+ *
+ * If the server rejects the service request, it SHOULD send an
+ * appropriate SSH_MSG_DISCONNECT message and MUST disconnect.
+ */
+ if (currentService == null) {
+ throw new SshException(SshConstants.SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE, "Unknown service: " + name);
+ }
}
@Override
[6/6] mina-sshd git commit: Added more detailed log messages as to
the authentication progress
Posted by lg...@apache.org.
Added more detailed log messages as to the authentication progress
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/0371baef
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/0371baef
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/0371baef
Branch: refs/heads/master
Commit: 0371baefc52c55961a2df43af5f86b5add5c71b8
Parents: 4cdbefc
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Wed Dec 9 12:02:16 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Wed Dec 9 12:02:16 2015 +0200
----------------------------------------------------------------------
.../auth/UserAuthKeyboardInteractive.java | 36 ++++++---
.../client/session/ClientUserAuthService.java | 78 +++++++++++++-------
.../auth/UserAuthKeyboardInteractive.java | 32 ++++++--
.../apache/sshd/server/auth/UserAuthNone.java | 3 +
.../sshd/server/auth/UserAuthPassword.java | 6 +-
.../sshd/server/auth/UserAuthPublicKey.java | 68 +++++++++++------
.../server/session/ServerUserAuthService.java | 76 +++++++++++++------
7 files changed, 213 insertions(+), 86 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0371baef/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 553a544..203c3d1 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
@@ -160,6 +160,9 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
String[] rep = getUserResponses(name, instruction, language_tag, prompt, echo);
if (rep == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("process({})[{}] no responses for {}", session, service, name);
+ }
return false;
}
@@ -173,19 +176,24 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
* However it is the server's (!) responsibility to fail, so we only warn...
*/
if (num != rep.length) {
- log.warn("process({}) Mismatched prompts ({}) vs. responses count ({})", session, num, rep.length);
+ log.warn("process({})[{}] Mismatched prompts ({}) vs. responses count ({})",
+ session, service, num, rep.length);
}
buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE, BufferUtils.clear(buffer));
buffer.putInt(rep.length);
- for (String r : rep) {
+ for (int index = 0; index < rep.length; index++) {
+ String r = rep[index];
+ if (log.isTraceEnabled()) {
+ log.trace("process({})[{}] response #{}: {}", session, service, index + 1, r);
+ }
buffer.putString(r);
}
session.writePacket(buffer);
return true;
}
- throw new IllegalStateException("process(" + session + ")[" + service + ")"
+ throw new IllegalStateException("process(" + session + ")[" + service + "]"
+ " received unknown packet: cmd=" + SshConstants.getCommandMessageName(cmd));
}
@@ -221,20 +229,30 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
* a warning...)
*/
protected String[] getUserResponses(String name, String instruction, String lang, String[] prompt, boolean[] echo) {
+ ClientSession session = getClientSession();
int num = GenericUtils.length(prompt);
if (num == 0) {
+ if (log.isDebugEnabled()) {
+ log.debug("getUserResponses({}) no prompts for interaction={}", session, name);
+ }
return GenericUtils.EMPTY_STRING_ARRAY;
}
String candidate = getCurrentPasswordCandidate();
if (useCurrentPassword(candidate, name, instruction, lang, prompt, echo)) {
- return new String[]{candidate};
- } else {
- ClientSession session = getClientSession();
- UserInteraction ui = session.getUserInteraction();
- if ((ui != null) && ui.isInteractionAllowed(session)) {
- return ui.interactive(session, name, instruction, lang, prompt, echo);
+ if (log.isDebugEnabled()) {
+ log.debug("getUserResponses({}) use password candidate for interaction={}", session, name);
}
+ return new String[]{candidate};
+ }
+
+ UserInteraction ui = session.getUserInteraction();
+ if ((ui != null) && ui.isInteractionAllowed(session)) {
+ return ui.interactive(session, name, instruction, lang, prompt, echo);
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("getUserResponses({}) no user interaction for name={}", session, name);
}
return null;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0371baef/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 0e2fe5c..1e3ca06 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
@@ -52,7 +52,7 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
*/
private final AuthFuture authFuture;
- private final ClientSessionImpl session;
+ private final ClientSessionImpl clientSession;
private List<Object> identities;
private String service;
@@ -68,27 +68,35 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
if (!(s instanceof ClientSessionImpl)) {
throw new IllegalStateException("Client side service used on server side");
}
- session = (ClientSessionImpl) s;
- authFuture = new DefaultAuthFuture(session.getLock());
- authFactories = session.getUserAuthFactories();
+ clientSession = (ClientSessionImpl) s;
+ authFuture = new DefaultAuthFuture(clientSession.getLock());
+ authFactories = clientSession.getUserAuthFactories();
clientMethods = new ArrayList<>();
- String prefs = PropertyResolverUtils.getString(session, ClientAuthenticationManager.PREFERRED_AUTHS);
- if (!GenericUtils.isEmpty(prefs)) {
- for (String pref : prefs.split(",")) {
+ String prefs = PropertyResolverUtils.getString(s, ClientAuthenticationManager.PREFERRED_AUTHS);
+ if (GenericUtils.isEmpty(prefs)) {
+ for (NamedFactory<UserAuth> factory : authFactories) {
+ clientMethods.add(factory.getName());
+ }
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("ClientUserAuthService({}) use configured preferrences: {}", s, prefs);
+ }
+
+ for (String pref : GenericUtils.split(prefs, ',')) {
NamedFactory<UserAuth> factory = NamedResource.Utils.findByName(pref, String.CASE_INSENSITIVE_ORDER, authFactories);
if (factory != null) {
clientMethods.add(pref);
} else {
if (log.isDebugEnabled()) {
- log.debug("ClientUserAuthService({}) skip unknown prefered authentication method: {}", s, pref);
+ log.debug("ClientUserAuthService({}) skip unknown preferred authentication method: {}", s, pref);
}
}
}
- } else {
- for (NamedFactory<UserAuth> factory : authFactories) {
- clientMethods.add(factory.getName());
- }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("ClientUserAuthService({}) client methods: {}", s, clientMethods);
}
}
@@ -99,7 +107,7 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
@Override
public ClientSession getClientSession() {
- return session;
+ return clientSession;
}
@Override
@@ -111,12 +119,14 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
this.identities = new ArrayList<>(identities);
this.service = service;
+ ClientSession session = getClientSession();
+ String username = session.getUsername();
if (log.isDebugEnabled()) {
- log.debug("auth({})[{}] Send SSH_MSG_USERAUTH_REQUEST for 'none'", getClientSession(), service);
+ log.debug("auth({})[{}] Send SSH_MSG_USERAUTH_REQUEST for 'none'", session, service);
}
- String username = session.getUsername();
+
Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST, username.length() + service.length() + Integer.SIZE);
- buffer.putString(session.getUsername());
+ buffer.putString(username);
buffer.putString(service);
buffer.putString("none");
session.writePacket(buffer);
@@ -126,6 +136,7 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
@Override
public void process(int cmd, Buffer buffer) throws Exception {
+ ClientSession session = getClientSession();
if (this.authFuture.isSuccess()) {
throw new IllegalStateException("UserAuth message delivered to authenticated client");
} else if (this.authFuture.isDone()) {
@@ -159,41 +170,51 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
*/
protected void processUserAuth(Buffer buffer) throws Exception {
int cmd = buffer.getUByte();
+ ClientSession session = getClientSession();
if (cmd == SshConstants.SSH_MSG_USERAUTH_SUCCESS) {
if (log.isDebugEnabled()) {
log.debug("processUserAuth({}) SSH_MSG_USERAUTH_SUCCESS Succeeded with {}",
- getClientSession(), userAuth);
+ session, userAuth);
}
if (userAuth != null) {
- userAuth.destroy();
- userAuth = null;
+ try {
+ userAuth.destroy();
+ } finally {
+ userAuth = null;
+ }
}
session.setAuthenticated();
- session.switchToNextService();
+ ((ClientSessionImpl) session).switchToNextService();
// Will wake up anyone sitting in waitFor
authFuture.setAuthed(true);
return;
}
+
if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
String mths = buffer.getString();
boolean partial = buffer.getBoolean();
if (log.isDebugEnabled()) {
log.debug("processUserAuth({}) Received SSH_MSG_USERAUTH_FAILURE - partial={}, methods={}",
- getClientSession(), partial, mths);
+ session, partial, mths);
}
if (partial || (serverMethods == null)) {
serverMethods = Arrays.asList(GenericUtils.split(mths, ','));
if (userAuth != null) {
- userAuth.destroy();
- userAuth = null;
+ try {
+ userAuth.destroy();
+ } finally {
+ userAuth = null;
+ }
}
}
tryNext();
return;
}
+
if (userAuth == null) {
- throw new IllegalStateException("Received unknown packet");
+ throw new IllegalStateException("Received unknown packet: " + SshConstants.getCommandMessageName(cmd));
}
+
buffer.rpos(buffer.rpos() - 1);
if (!userAuth.process(buffer)) {
tryNext();
@@ -201,6 +222,7 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
}
protected void tryNext() throws Exception {
+ ClientSession session = getClientSession();
// Loop until we find something to try
while (true) {
if (userAuth == null) {
@@ -218,10 +240,12 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
if (currentMethod >= clientMethods.size()) {
if (log.isDebugEnabled()) {
- log.debug("tryNext({}) exhausted all methods", getClientSession());
+ log.debug("tryNext({}) exhausted all methods - client={}, server={}",
+ session, clientMethods, serverMethods);
}
- authFuture.setAuthed(false);
+ // also wake up anyone sitting in waitFor
+ authFuture.setException(new SshException(SshConstants.SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, "No more authentication methods available"));
return;
}
@@ -231,7 +255,7 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
throw new UnsupportedOperationException("Failed to find a user-auth factory for method=" + method);
}
if (log.isDebugEnabled()) {
- log.debug("tryNext({}) attempting method={}", getClientSession(), method);
+ log.debug("tryNext({}) attempting method={}", session, method);
}
userAuth.init(session, service, identities);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0371baef/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 a384520..9639929 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
@@ -24,6 +24,7 @@ import java.util.List;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.server.auth.keyboard.InteractiveChallenge;
@@ -45,13 +46,15 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
@Override
protected Boolean doAuth(Buffer buffer, boolean init) throws Exception {
ServerSession session = getServerSession();
+ String username = getUsername();
KeyboardInteractiveAuthenticator auth = session.getKeyboardInteractiveAuthenticator();
if (init) {
String lang = buffer.getString();
String subMethods = buffer.getString();
if (auth == null) {
if (log.isDebugEnabled()) {
- log.debug("doAuth({}) no interactive authenticator to generate challenge", session);
+ log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive authenticator to generate challenge",
+ username, session, subMethods, lang);
}
return false;
}
@@ -59,11 +62,19 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
InteractiveChallenge challenge = auth.generateChallenge(session, getUsername(), lang, subMethods);
if (challenge == null) {
if (log.isDebugEnabled()) {
- log.debug("doAuth({}) no interactive challenge generated", session);
+ log.debug("doAuth({}@{})[methods={}, lang={}] - no interactive challenge generated",
+ username, session, subMethods, lang);
}
return false;
}
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{})[methods={}, lang={}] challenge name={}, instruction={}, lang={}, num. prompts={}",
+ username, session, subMethods, lang,
+ challenge.getInteractionName(), challenge.getInteractionInstruction(),
+ challenge.getLanguageTag(), GenericUtils.size(challenge.getPrompts()));
+ }
+
// Prompt for password
buffer = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST, BufferUtils.clear(buffer));
challenge.append(buffer);
@@ -78,17 +89,28 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
int num = buffer.getInt();
List<String> responses = (num <= 0) ? Collections.<String>emptyList() : new ArrayList<String>(num);
for (int index = 0; index < num; index++) {
- responses.add(buffer.getString());
+ String value = buffer.getString();
+ if (log.isTraceEnabled()) {
+ log.trace("doAuth({}@{}) response #{}: {}", username, session, index + 1, value);
+ }
+ responses.add(value);
}
if (auth == null) {
if (log.isDebugEnabled()) {
- log.debug("doAuth({}) no interactive authenticator to validate responses", session);
+ log.debug("doAuth({}@{}) no interactive authenticator to validate {} responses",
+ username, session, num);
}
return false;
}
- return auth.authenticate(session, getUsername(), responses);
+ boolean authed = auth.authenticate(session, username, responses);
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) authenticate {} responses result: {}",
+ username, session, num, authed);
+ }
+
+ return authed;
}
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0371baef/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
index 8cc708e..8b20eed 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
@@ -34,6 +34,9 @@ public class UserAuthNone extends AbstractUserAuth {
@Override
public Boolean doAuth(Buffer buffer, boolean init) {
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) init={}", getUsername(), getServerSession(), init);
+ }
return Boolean.TRUE;
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0371baef/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 d59720b..b0e72d4 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
@@ -77,7 +77,11 @@ public class UserAuthPassword extends AbstractUserAuth {
}
try {
- return auth.authenticate(username, password, session);
+ boolean authed = auth.authenticate(username, password, session);
+ if (log.isDebugEnabled()) {
+ log.debug("checkPassword({}) authentication result: {}", session, authed);
+ }
+ return authed;
} catch (PasswordChangeRequiredException e) {
if (log.isDebugEnabled()) {
log.debug("checkPassword({}) password change required: {}", session, e.getMessage());
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0371baef/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 5299a84..08b05b7 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
@@ -55,10 +55,11 @@ public class UserAuthPublicKey extends AbstractUserAuth {
buffer.wpos(buffer.rpos() + len);
ServerSession session = getServerSession();
+ String username = getUsername();
PublicKey key = buffer.getRawPublicKey();
if (log.isDebugEnabled()) {
- log.debug("doAuth({}) verify key type={}, fingerprint={}",
- session, alg, KeyUtils.getFingerPrint(key));
+ log.debug("doAuth({}@{}) verify key type={}, fingerprint={}",
+ username, session, alg, KeyUtils.getFingerPrint(key));
}
Signature verifier = ValidateUtils.checkNotNull(
@@ -72,38 +73,63 @@ public class UserAuthPublicKey extends AbstractUserAuth {
PublickeyAuthenticator authenticator = session.getPublickeyAuthenticator();
if (authenticator == null) {
if (log.isDebugEnabled()) {
- log.debug("doAuth({}) no authenticator", session);
+ log.debug("doAuth({}@{}) key type={}, fingerprint={} - no authenticator",
+ username, session, alg, KeyUtils.getFingerPrint(key));
}
return false;
}
- if (!authenticator.authenticate(getUsername(), key, session)) {
+ boolean authed = authenticator.authenticate(username, key, session);
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) key type={}, fingerprint={} - authentication result: {}",
+ username, session, alg, KeyUtils.getFingerPrint(key), authed);
+ }
+ if (!authed) {
return Boolean.FALSE;
}
if (!hasSig) {
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) send SSH_MSG_USERAUTH_PK_OK for key type={}, fingerprint={}",
+ username, session, alg, KeyUtils.getFingerPrint(key));
+ }
+
Buffer buf = session.prepareBuffer(SshConstants.SSH_MSG_USERAUTH_PK_OK, BufferUtils.clear(buffer));
buf.putString(alg);
buf.putRawBytes(buffer.array(), oldPos, 4 + len);
session.writePacket(buf);
return null;
- } else {
- Buffer buf = new ByteArrayBuffer();
- buf.putBytes(session.getKex().getH());
- buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
- buf.putString(getUsername());
- buf.putString(getService());
- buf.putString(getName());
- buf.putBoolean(true);
- buf.putString(alg);
- buffer.rpos(oldPos);
- buffer.wpos(oldPos + 4 + len);
- buf.putBuffer(buffer);
- verifier.update(buf.array(), buf.rpos(), buf.available());
- if (!verifier.verify(sig)) {
- throw new Exception("Key verification failed");
- }
- return Boolean.TRUE;
}
+
+ // verify signature
+ Buffer buf = new ByteArrayBuffer();
+ buf.putBytes(session.getKex().getH());
+ buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST);
+ buf.putString(username);
+ buf.putString(getService());
+ buf.putString(getName());
+ buf.putBoolean(true);
+ buf.putString(alg);
+ buffer.rpos(oldPos);
+ buffer.wpos(oldPos + 4 + len);
+ buf.putBuffer(buffer);
+ verifier.update(buf.array(), buf.rpos(), buf.available());
+ if (log.isTraceEnabled()) {
+ log.trace("doAuth({}@{}) key type={}, fingerprint={} - verification data={}",
+ username, session, alg, KeyUtils.getFingerPrint(key), buf.printHex());
+ log.trace("doAuth({}@{}) key type={}, fingerprint={} - expected signature={}",
+ username, session, alg, KeyUtils.getFingerPrint(key), BufferUtils.printHex(sig));
+ }
+
+ if (!verifier.verify(sig)) {
+ throw new Exception("Key verification failed");
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("doAuth({}@{}) key type={}, fingerprint={} - verified",
+ username, session, alg, KeyUtils.getFingerPrint(key));
+ }
+
+ return Boolean.TRUE;
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0371baef/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 977bdc4..a67b40f 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
@@ -45,7 +45,7 @@ import org.apache.sshd.server.auth.UserAuthNoneFactory;
*/
public class ServerUserAuthService extends AbstractCloseable implements Service, ServerSessionHolder {
- private final ServerSession session;
+ private final ServerSession serverSession;
private List<NamedFactory<UserAuth>> userAuthFactories;
private List<List<String>> authMethods;
private String authUserName;
@@ -62,22 +62,25 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
throw new SshException("Session already authenticated");
}
- this.session = (ServerSession) s;
- maxAuthRequests = PropertyResolverUtils.getIntProperty(session, ServerAuthenticationManager.MAX_AUTH_REQUESTS, ServerAuthenticationManager.DEFAULT_MAX_AUTH_REQUESTS);
+ serverSession = (ServerSession) s;
+ maxAuthRequests = PropertyResolverUtils.getIntProperty(s, ServerAuthenticationManager.MAX_AUTH_REQUESTS, ServerAuthenticationManager.DEFAULT_MAX_AUTH_REQUESTS);
- List<NamedFactory<UserAuth>> factories = session.getUserAuthFactories();
+ List<NamedFactory<UserAuth>> factories = serverSession.getUserAuthFactories();
userAuthFactories = new ArrayList<>(factories);
// Get authentication methods
authMethods = new ArrayList<>();
- String mths = PropertyResolverUtils.getString(session, ServerFactoryManager.AUTH_METHODS);
+ String mths = PropertyResolverUtils.getString(s, ServerFactoryManager.AUTH_METHODS);
if (GenericUtils.isEmpty(mths)) {
for (NamedFactory<UserAuth> uaf : factories) {
authMethods.add(new ArrayList<>(Collections.singletonList(uaf.getName())));
}
} else {
+ if (log.isDebugEnabled()) {
+ log.debug("ServerUserAuthService({}) using configured methods={}", s, mths);
+ }
for (String mthl : mths.split("\\s")) {
- authMethods.add(new ArrayList<>(Arrays.asList(mthl.split(","))));
+ authMethods.add(new ArrayList<>(Arrays.asList(GenericUtils.split(mthl, ','))));
}
}
// Verify all required methods are supported
@@ -91,7 +94,8 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
}
if (log.isDebugEnabled()) {
- log.debug("Authorized authentication methods: {}", NamedResource.Utils.getNames(userAuthFactories));
+ log.debug("ServerUserAuthService({}) authorized authentication methods: {}",
+ s, NamedResource.Utils.getNames(userAuthFactories));
}
}
@@ -107,17 +111,21 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
@Override
public ServerSession getServerSession() {
- return session;
+ return serverSession;
}
@Override
public void process(int cmd, Buffer buffer) throws Exception {
Boolean authed = Boolean.FALSE;
+ ServerSession session = getServerSession();
if (cmd == SshConstants.SSH_MSG_USERAUTH_REQUEST) {
- if (this.currentAuth != null) {
- this.currentAuth.destroy();
- this.currentAuth = null;
+ if (currentAuth != null) {
+ try {
+ currentAuth.destroy();
+ } finally {
+ currentAuth = null;
+ }
}
String username = buffer.getString();
@@ -125,7 +133,7 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
String method = buffer.getString();
if (log.isDebugEnabled()) {
log.debug("process({}) Received SSH_MSG_USERAUTH_REQUEST user={}, service={}, method={}",
- getServerSession(), username, service, method);
+ session, username, service, method);
}
if (this.authUserName == null || this.authService == null) {
@@ -141,26 +149,30 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
// TODO: verify that the service is supported
this.authMethod = method;
if (nbAuthRequests++ > maxAuthRequests) {
- session.disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too many authentication failures");
+ session.disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too many authentication failures: " + nbAuthRequests);
return;
}
if (log.isDebugEnabled()) {
- log.debug("process({}) Authenticating user '{}' with service '{}' and method '{}'",
- getServerSession(), username, service, method);
+ log.debug("process({}) Authenticating user '{}' with service '{}' and method '{}' (attempt {} / {})",
+ session, username, service, method, nbAuthRequests, maxAuthRequests);
}
NamedFactory<UserAuth> factory = NamedResource.Utils.findByName(method, String.CASE_INSENSITIVE_ORDER, userAuthFactories);
if (factory != null) {
- currentAuth = factory.create();
+ currentAuth = ValidateUtils.checkNotNull(factory.create(), "No authenticator created for method=%s", method);
try {
authed = currentAuth.auth(session, username, service, buffer);
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("process({}) Failed ({}) to authenticate using method={}: {}",
- getServerSession(), e.getClass().getSimpleName(), method, e.getMessage());
+ session, e.getClass().getSimpleName(), method, e.getMessage());
}
}
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("process({}) no authentication factory for method={}", session, method);
+ }
}
} else {
if (this.currentAuth == null) {
@@ -169,8 +181,9 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
}
if (log.isDebugEnabled()) {
log.debug("process({}) Received authentication message={} for mechanism={}",
- getServerSession(), SshConstants.getCommandMessageName(cmd), currentAuth.getName());
+ session, SshConstants.getCommandMessageName(cmd), currentAuth.getName());
}
+
buffer.rpos(buffer.rpos() - 1);
try {
authed = currentAuth.next(buffer);
@@ -178,7 +191,7 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
// Continue
if (log.isDebugEnabled()) {
log.debug("process({}) Failed ({}) to authenticate using method={}: {}",
- getServerSession(), e.getClass().getSimpleName(), currentAuth.getName(), e.getMessage());
+ session, e.getClass().getSimpleName(), currentAuth.getName(), e.getMessage());
}
}
}
@@ -196,12 +209,13 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
String username = (currentAuth == null) ? null : currentAuth.getUsername();
if (log.isDebugEnabled()) {
log.debug("handleAuthenticationInProgress({}@{}) {}",
- username, session, SshConstants.getCommandMessageName(cmd));
+ username, getServerSession(), SshConstants.getCommandMessageName(cmd));
}
}
protected void handleAuthenticationSuccess(int cmd, Buffer buffer) throws Exception {
String username = ValidateUtils.checkNotNull(currentAuth, "No current auth").getUsername();
+ ServerSession session = getServerSession();
if (log.isDebugEnabled()) {
log.debug("handleAuthenticationSuccess({}@{}) {}",
username, session, SshConstants.getCommandMessageName(cmd));
@@ -242,6 +256,11 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_BANNER, welcomeBanner.length() + lang.length() + Long.SIZE);
buffer.putString(welcomeBanner);
buffer.putString(lang);
+
+ if (log.isDebugEnabled()) {
+ log.debug("handleAuthenticationSuccess({}@{}) send banner (length={}, lang={})",
+ username, session, welcomeBanner.length(), lang);
+ }
session.writePacket(buffer);
}
@@ -263,7 +282,12 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
sb.append(l.get(0));
}
}
- buffer.putString(sb.toString());
+
+ String remaining = sb.toString();
+ if (log.isDebugEnabled()) {
+ log.debug("handleAuthenticationSuccess({}@{}) remaining methods={}", username, session, remaining);
+ }
+ buffer.putString(remaining);
buffer.putBoolean(true); // partial success ...
session.writePacket(buffer);
}
@@ -277,6 +301,7 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
protected void handleAuthenticationFailure(int cmd, Buffer buffer) throws Exception {
String username = (currentAuth == null) ? null : currentAuth.getUsername();
+ ServerSession session = getServerSession();
if (log.isDebugEnabled()) {
log.debug("handleAuthenticationFailure({}@{}) {}",
username, session, SshConstants.getCommandMessageName(cmd));
@@ -295,7 +320,12 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
}
}
}
- buffer.putString(sb.toString());
+
+ String remaining = sb.toString();
+ if (log.isDebugEnabled()) {
+ log.debug("handleAuthenticationFailure({}@{}) remaining methods: {}", username, session, remaining);
+ }
+ buffer.putString(remaining);
buffer.putBoolean(false); // no partial success ...
session.writePacket(buffer);
@@ -309,6 +339,6 @@ public class ServerUserAuthService extends AbstractCloseable implements Service,
}
public ServerFactoryManager getFactoryManager() {
- return session.getFactoryManager();
+ return serverSession.getFactoryManager();
}
}
[5/6] mina-sshd git commit: [SSHD-610] Disconnect reason should be
propagated as error message
Posted by lg...@apache.org.
[SSHD-610] Disconnect reason should be propagated as error message
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/4cdbefc6
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/4cdbefc6
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/4cdbefc6
Branch: refs/heads/master
Commit: 4cdbefc61c80f4d089dfb8c48fe19258cfa2ef24
Parents: d99d480
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Wed Dec 9 12:01:15 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Wed Dec 9 12:01:15 2015 +0200
----------------------------------------------------------------------
.../apache/sshd/client/session/ClientSessionImpl.java | 11 +++++++++++
1 file changed, 11 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/4cdbefc6/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 d10e8cd..5a0a0f5 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
@@ -146,6 +146,17 @@ public class ClientSessionImpl extends AbstractClientSession {
super.exceptionCaught(t);
}
+ @Override
+ protected void handleDisconnect(int code, String msg, String lang, Buffer buffer) throws Exception {
+ synchronized (lock) {
+ if (!authFuture.isDone()) {
+ authFuture.setException(new SshException(code, msg));
+ }
+ }
+
+ super.handleDisconnect(code, msg, lang, buffer);
+ }
+
protected String nextServiceName() {
synchronized (lock) {
return nextServiceFactory.getName();