You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2013/07/17 16:32:14 UTC
[1/4] git commit: [SSHD-195] Fix welcome banner implementation
Updated Branches:
refs/heads/master 25995ffe4 -> a49dee379
[SSHD-195] Fix welcome banner implementation
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/5bb83665
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/5bb83665
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/5bb83665
Branch: refs/heads/master
Commit: 5bb836651ad5e805fd367f375a574f92d2085776
Parents: 25995ff
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 17 09:00:49 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 17 09:00:49 2013 +0200
----------------------------------------------------------------------
.../apache/sshd/server/session/ServerSession.java | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5bb83665/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index eead762..f095ed7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -66,7 +66,6 @@ public class ServerSession extends AbstractSession {
private boolean allowMoreSessions = true;
private final AgentForwardSupport agentForward;
private final X11ForwardSupport x11Forward;
- private String welcomeBanner = null;
private HandshakingUserAuth currentAuth;
@@ -79,7 +78,6 @@ public class ServerSession extends AbstractSession {
idleTimeout = getIntProperty(ServerFactoryManager.IDLE_TIMEOUT, idleTimeout);
agentForward = new AgentForwardSupport(this);
x11Forward = new X11ForwardSupport(this);
- welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
log.info("Session created from {}", ioSession.getRemoteAddress());
sendServerIdentification();
sendKexInit();
@@ -405,12 +403,6 @@ public class ServerSession extends AbstractSession {
} else {
log.debug("Unsupported authentication method '{}'", method);
- if (welcomeBanner != null) {
- buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
- buffer.putString(welcomeBanner);
- buffer.putString("\n");
- writePacket(buffer);
- }
}
} else {
try {
@@ -451,6 +443,14 @@ public class ServerSession extends AbstractSession {
}
}
+ String welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
+ if (welcomeBanner != null) {
+ buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
+ buffer.putString(welcomeBanner);
+ buffer.putString("\n");
+ writePacket(buffer);
+ }
+
buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_SUCCESS, 0);
writePacket(buffer);
setState(State.Running);
[4/4] git commit: [SSHD-234] Support partial authentications on the
server side
Posted by gn...@apache.org.
[SSHD-234] Support partial authentications on the server side
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/a49dee37
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/a49dee37
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/a49dee37
Branch: refs/heads/master
Commit: a49dee379f8dab72421595ca28ececfb0ce0b7b2
Parents: 1937ee8
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 17 16:31:48 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 17 16:31:48 2013 +0200
----------------------------------------------------------------------
.../main/java/org/apache/sshd/SshServer.java | 1 +
.../sshd/client/session/ClientSessionImpl.java | 12 +-
.../apache/sshd/server/HandshakingUserAuth.java | 20 +-
.../sshd/server/ServerFactoryManager.java | 14 ++
.../java/org/apache/sshd/server/UserAuth.java | 2 +-
.../apache/sshd/server/auth/UserAuthNone.java | 2 +-
.../sshd/server/auth/UserAuthPassword.java | 7 +-
.../sshd/server/auth/UserAuthPublicKey.java | 6 +-
.../sshd/server/auth/gss/UserAuthGSS.java | 30 +--
.../sshd/server/session/ServerSession.java | 224 ++++++++++++-------
.../org/apache/sshd/AuthenticationTest.java | 161 +++++++++++++
11 files changed, 353 insertions(+), 126 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
index b5c95b6..a8b4919 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
@@ -551,6 +551,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setPort(port);
+ sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD");
if (SecurityUtils.isBouncyCastleRegistered()) {
sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider("key.pem"));
} else {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index 37f7175..2949403 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -85,7 +85,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
return kex;
}
- public AuthFuture authAgent(String username) throws IOException {
+ public AuthFuture authAgent(String user) throws IOException {
synchronized (lock) {
if (closeFuture.isClosed()) {
throw new IllegalStateException("Session is closed");
@@ -104,7 +104,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
throw new IllegalStateException("Session is closed");
}
authFuture = new DefaultAuthFuture(lock);
- userAuth = new UserAuthAgent(this, username);
+ userAuth = new UserAuthAgent(this, user);
setState(State.UserAuth);
switch (userAuth.next(null)) {
@@ -126,7 +126,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
}
}
- public AuthFuture authPassword(String username, String password) throws IOException {
+ public AuthFuture authPassword(String user, String password) throws IOException {
synchronized (lock) {
if (closeFuture.isClosed()) {
throw new IllegalStateException("Session is closed");
@@ -142,7 +142,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
throw new IllegalStateException("Session is closed");
}
authFuture = new DefaultAuthFuture(lock);
- userAuth = new UserAuthPassword(this, username, password);
+ userAuth = new UserAuthPassword(this, user, password);
setState(State.UserAuth);
switch (userAuth.next(null)) {
@@ -164,7 +164,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
}
}
- public AuthFuture authPublicKey(String username, KeyPair key) throws IOException {
+ public AuthFuture authPublicKey(String user, KeyPair key) throws IOException {
synchronized (lock) {
if (closeFuture.isClosed()) {
throw new IllegalStateException("Session is closed");
@@ -180,7 +180,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
throw new IllegalStateException("Session is closed");
}
authFuture = new DefaultAuthFuture(lock);
- userAuth = new UserAuthPublicKey(this, username, key);
+ userAuth = new UserAuthPublicKey(this, user, key);
setState(State.UserAuth);
switch (userAuth.next(null)) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
index 625f7ba..d0bf5d9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
@@ -31,34 +31,16 @@ import org.apache.sshd.server.session.ServerSession;
public interface HandshakingUserAuth extends UserAuth {
/**
- * Set the service name from the original request. This may be required for MIC verification later.
- *
- * @param service The service name
- */
-
- void setServiceName(String service);
-
- /**
- * Check whether a particular message is handled here.
- *
- * @param msg The message
- * @return <code>true</code> if the message is handled
- */
-
- boolean handles(SshConstants.Message msg);
-
- /**
* Handle another step in the authentication process.
*
* @param session the current ssh session
- * @param msg The message type
* @param buffer the request buffer containing parameters specific to this request
* @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
* is not finished yet
* @throws Exception if the authentication fails
*/
- Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception;
+ Boolean next(ServerSession session, Buffer buffer) throws Exception;
/**
* Get a user name which has been derived from the handshaking process, or the intial name if
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
index 3f1e74b..f179a15 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
@@ -68,6 +68,20 @@ public interface ServerFactoryManager extends FactoryManager {
public static final String WELCOME_BANNER = "welcome-banner";
/**
+ * This key is used when configuring multi-step authentications.
+ * The value needs to be a blank separated list of comma separated list
+ * of authentication method names.
+ * For example, an argument of
+ * <code>publickey,password publickey,keyboard-interactive</code>
+ * would require the user to complete public key authentication,
+ * followed by either password or keyboard interactive authentication.
+ * Only methods that are next in one or more lists are offered at each
+ * stage, so for this example, it would not be possible to attempt
+ * password or keyboard-interactive authentication before public key.
+ */
+ public static final String AUTH_METHODS = "auth-methods";
+
+ /**
* Retrieve the list of named factories for <code>UserAuth<code> objects.
*
* @return a list of named <code>UserAuth</code> factories, never <code>null</code>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
index 8afb799..0bb9940 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/UserAuth.java
@@ -42,6 +42,6 @@ public interface UserAuth {
* is not finished yet
* @throws Exception if the authentication fails
*/
- Boolean auth(ServerSession session, String username, Buffer buffer) throws Exception;
+ Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
index 0297cef..3d96c9e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthNone.java
@@ -39,7 +39,7 @@ public class UserAuthNone implements UserAuth {
}
}
- public Boolean auth(ServerSession session, String username, Buffer buffer) {
+ public Boolean auth(ServerSession session, String username, String service, Buffer buffer) {
return true;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
index 39c2f49..b2c60e2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPassword.java
@@ -19,6 +19,8 @@
package org.apache.sshd.server.auth;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
import org.apache.sshd.common.util.Buffer;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.UserAuth;
@@ -40,7 +42,10 @@ public class UserAuthPassword implements UserAuth {
}
}
- public Boolean auth(ServerSession session, String username, Buffer buffer) throws Exception {
+ public Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception {
+ if (!"ssh-connection".equals(service)) {
+ throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Unsupported service '" + service + "'");
+ }
boolean newPassword = buffer.getBoolean();
if (newPassword) {
throw new IllegalStateException("Password changes are not supported");
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
index cb7a907..f9349a7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/UserAuthPublicKey.java
@@ -25,6 +25,7 @@ import org.apache.sshd.common.KeyPairProvider;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.Signature;
import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
import org.apache.sshd.common.util.Buffer;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.server.UserAuth;
@@ -46,7 +47,10 @@ public class UserAuthPublicKey implements UserAuth {
}
}
- public Boolean auth(ServerSession session, String username, Buffer buffer) throws Exception {
+ public Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception {
+ if (!"ssh-connection".equals(service)) {
+ throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Unsupported service '" + service + "'");
+ }
boolean hasSig = buffer.getBoolean();
String alg = buffer.getString();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
index afcca3a..02f2458 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
@@ -20,6 +20,7 @@ package org.apache.sshd.server.auth.gss;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
import org.apache.sshd.common.util.Buffer;
import org.apache.sshd.server.HandshakingUserAuth;
import org.apache.sshd.server.UserAuth;
@@ -39,7 +40,6 @@ import org.slf4j.LoggerFactory;
* <p/>
* Several methods are available for overriding in specific circumstances.
*/
-
public class UserAuthGSS implements HandshakingUserAuth {
// Oids for the Kerberos 5 mechanism and principal
@@ -88,10 +88,11 @@ public class UserAuthGSS implements HandshakingUserAuth {
* @throws Exception If something went wrong
*/
- public Boolean auth(ServerSession sess, String user, Buffer buff) throws Exception {
+ public Boolean auth(ServerSession sess, String user, String service, Buffer buff) throws Exception {
GSSAuthenticator auth = getAuthenticator(sess);
this.user = user;
+ this.service = service;
// Get mechanism count from buffer and look for Kerberos 5.
@@ -136,22 +137,11 @@ public class UserAuthGSS implements HandshakingUserAuth {
}
/**
- * Set the service name from the original request. This may be required for MIC verification later.
- *
- * @param service The service name
- */
-
- public void setServiceName(String service) {
- this.service = service;
- }
-
- /**
* Check whether a particular message is handled here.
*
* @param msg The message
* @return <code>true</code> if the message is handled
*/
-
public boolean handles(SshConstants.Message msg) {
return msg == SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE || msg == SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC && ctxt.isEstablished();
}
@@ -165,8 +155,13 @@ public class UserAuthGSS implements HandshakingUserAuth {
* is not finished yet
* @throws Exception if the authentication fails
*/
+ public Boolean next(ServerSession session, Buffer buffer) throws Exception {
+
+ SshConstants.Message msg = buffer.getCommand();
+ if (!handles(msg)) {
+ throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Packet not supported by user authentication method");
+ }
- public Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception {
GSSAuthenticator auth = getAuthenticator(session);
log.debug("In krb5.next: msg = " + msg);
@@ -229,7 +224,7 @@ public class UserAuthGSS implements HandshakingUserAuth {
session.writePacket(b);
return null;
} else {
- return Boolean.valueOf(established);
+ return established;
}
}
}
@@ -240,7 +235,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
*
* @return The user name
*/
-
public String getUserName() throws GSSException {
return identity;
}
@@ -248,7 +242,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
/**
* Free any system resources used by the module.
*/
-
public void destroy() {
if (creds != null) {
try {
@@ -275,7 +268,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
* @return The GSS authenticator
* @throws Exception If no GSS authenticator is defined
*/
-
private GSSAuthenticator getAuthenticator(ServerSession session) throws Exception {
GSSAuthenticator ga = session.getServerFactoryManager().getGSSAuthenticator();
@@ -292,7 +284,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
* @param rep The string form
* @return The Oid
*/
-
private static Oid createOID(String rep) {
try {
return new Oid(rep);
@@ -305,7 +296,6 @@ public class UserAuthGSS implements HandshakingUserAuth {
/**
* Factory class.
*/
-
public static class Factory implements NamedFactory<UserAuth> {
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index 4582519..75f14d4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -23,6 +23,8 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.KeyPair;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
@@ -30,6 +32,7 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.mina.core.session.IoSession;
+import org.apache.sshd.SshServer;
import org.apache.sshd.agent.common.AgentForwardSupport;
import org.apache.sshd.client.future.OpenFuture;
import org.apache.sshd.common.*;
@@ -67,9 +70,12 @@ public class ServerSession extends AbstractSession {
private final AgentForwardSupport agentForward;
private final X11ForwardSupport x11Forward;
- private HandshakingUserAuth currentAuth;
-
private List<NamedFactory<UserAuth>> userAuthFactories;
+ private List<List<String>> authMethods;
+ private String authUserName;
+ private String authMethod;
+ private String authService;
+ private HandshakingUserAuth currentAuth;
public ServerSession(FactoryManager server, IoSession ioSession) throws Exception {
super(server, ioSession);
@@ -183,7 +189,7 @@ public class ServerSession extends AbstractSession {
}
break;
case UserAuth:
- if (cmd != SshConstants.Message.SSH_MSG_USERAUTH_REQUEST && (currentAuth == null || !currentAuth.handles(cmd))) {
+ if (cmd != SshConstants.Message.SSH_MSG_USERAUTH_REQUEST && currentAuth == null) {
disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Protocol error: expected packet " + SshConstants.Message.SSH_MSG_USERAUTH_REQUEST + ", got " + cmd);
return;
}
@@ -358,113 +364,177 @@ public class ServerSession extends AbstractSession {
buffer.putString("ssh-userauth");
writePacket(buffer);
userAuthFactories = new ArrayList<NamedFactory<UserAuth>>(getServerFactoryManager().getUserAuthFactories());
+ // Get authentication methods
+ authMethods = new ArrayList<List<String>>();
+ String mths = getServerFactoryManager().getProperties().get(SshServer.AUTH_METHODS);
+ if (mths == null) {
+ for (NamedFactory<UserAuth> uaf : getServerFactoryManager().getUserAuthFactories()) {
+ authMethods.add(new ArrayList<String>(Collections.singletonList(uaf.getName())));
+ }
+ } else {
+ for (String mthl : mths.split("\\s")) {
+ authMethods.add(new ArrayList<String>(Arrays.asList(mthl.split(","))));
+ }
+ }
+ // Verify all required methods are supported
+ for (List<String> l : authMethods) {
+ for (String m : l) {
+ if (NamedFactory.Utils.get(userAuthFactories, m) == null) {
+ throw new SshException("Configured method is not supported: " + m);
+ }
+ }
+ }
log.debug("Authorized authentication methods: {}", NamedFactory.Utils.getNames(userAuthFactories));
setState(State.UserAuth);
+
} else {
- if (nbAuthRequests++ > maxAuthRequests) {
- throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too may authentication failures");
- }
- Boolean authed = null;
- String username = null;
+ UserAuth auth = this.currentAuth;
+ Boolean authed = Boolean.FALSE;
if (cmd == SshConstants.Message.SSH_MSG_USERAUTH_REQUEST) {
- username = buffer.getString();
+ if (this.currentAuth != null) {
+ this.currentAuth.destroy();
+ this.currentAuth = null;
+ }
- String svcName = buffer.getString();
+ String username = buffer.getString();
+ String service = buffer.getString();
String method = buffer.getString();
+ if (this.authUserName == null || this.authService == null) {
+ this.authUserName = username;
+ this.authService = service;
+ } else if (!this.authUserName.equals(username) || !this.authService.equals(service)) {
+ disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR,
+ "Change of username or service is not allowed (" + this.authUserName + ", " + this.authService + ") -> ("
+ + username + ", " + service + ")");
+ return;
+ }
+ this.authMethod = method;
+ if (nbAuthRequests++ > maxAuthRequests) {
+ disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too may authentication failures");
+ return;
+ }
- log.debug("Authenticating user '{}' with method '{}'", username, method);
+ log.debug("Authenticating user '{}' with service '{}' and method '{}'", new Object[] { username, service, method });
NamedFactory<UserAuth> factory = NamedFactory.Utils.get(userAuthFactories, method);
if (factory != null) {
- UserAuth auth = factory.create();
+ auth = factory.create();
try {
- authed = auth.auth(this, username, buffer);
- if (authed == null) {
- // authentication is still ongoing
- log.debug("Authentication not finished");
-
- if (auth instanceof HandshakingUserAuth) {
- currentAuth = (HandshakingUserAuth) auth;
-
- // GSSAPI needs the user name and service to verify the MIC
-
- currentAuth.setServiceName(svcName);
- }
- return;
- } else {
- log.debug(authed ? "Authentication succeeded" : "Authentication failed");
- }
+ authed = auth.auth(this, username, service, buffer);
} catch (Exception e) {
// Continue
- authed = false;
log.debug("Authentication failed: {}", e.getMessage());
}
-
- } else {
- log.debug("Unsupported authentication method '{}'", method);
}
- } else {
+ } else {
+ if (this.currentAuth == null) {
+ // This should not happen
+ throw new IllegalStateException();
+ }
+ buffer.rpos(buffer.rpos() - 1);
try {
- authed = currentAuth.next(this, cmd, buffer);
-
- if (authed == null) {
- // authentication is still ongoing
- log.debug("Authentication still not finished");
- return;
- } else if (authed.booleanValue()) {
- username = currentAuth.getUserName();
- }
+ authed = currentAuth.next(this, buffer);
} catch (Exception e) {
- // failed
- authed = false;
- log.debug("Authentication next failed: {}", e.getMessage());
+ // Continue
+ log.debug("Authentication failed: {}", e.getMessage());
}
}
- // No more handshakes now - clean up if necessary
+ if (authed == null) {
+ // authentication is still ongoing
+ log.debug("Authentication not finished");
+ if (auth instanceof HandshakingUserAuth) {
+ currentAuth = (HandshakingUserAuth) auth;
+ }
+ } else if (authed) {
+ log.debug("Authentication succeeded");
+ if (currentAuth != null) {
+ username = currentAuth.getUserName();
+ } else {
+ username = this.authUserName;
+ }
- if (currentAuth != null) {
- currentAuth.destroy();
- currentAuth = null;
- }
+ boolean success = false;
+ for (List<String> l : authMethods) {
+ if (!l.isEmpty() && l.get(0).equals(authMethod)) {
+ l.remove(0);
+ success |= l.isEmpty();
+ }
+ }
+ if (success) {
+ if (getFactoryManager().getProperties() != null) {
+ String maxSessionCountAsString = getFactoryManager().getProperties().get(ServerFactoryManager.MAX_CONCURRENT_SESSIONS);
+ if (maxSessionCountAsString != null) {
+ int maxSessionCount = Integer.parseInt(maxSessionCountAsString);
+ int currentSessionCount = getActiveSessionCountForUser(username);
+ if (currentSessionCount >= maxSessionCount) {
+ disconnect(SshConstants.SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE, "Too many concurrent connections");
+ return;
+ }
+ }
+ }
- if (authed != null && authed) {
+ String welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
+ if (welcomeBanner != null) {
+ buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
+ buffer.putString(welcomeBanner);
+ buffer.putString("en");
+ writePacket(buffer);
+ }
- if (getFactoryManager().getProperties() != null) {
- String maxSessionCountAsString = getFactoryManager().getProperties().get(ServerFactoryManager.MAX_CONCURRENT_SESSIONS);
- if (maxSessionCountAsString != null) {
- int maxSessionCount = Integer.parseInt(maxSessionCountAsString);
- int currentSessionCount = getActiveSessionCountForUser(username);
- if (currentSessionCount >= maxSessionCount) {
- disconnect(SshConstants.SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE, "Too many concurrent connections");
- return;
+ buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_SUCCESS, 0);
+ writePacket(buffer);
+ setState(State.Running);
+ this.authed = true;
+ unscheduleAuthTimer();
+ scheduleIdleTimer();
+ log.info("Session {}@{} authenticated", getUsername(), getIoSession().getRemoteAddress());
+
+ } else {
+ buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_FAILURE, 0);
+ StringBuilder sb = new StringBuilder();
+ for (List<String> l : authMethods) {
+ if (!l.isEmpty()) {
+ if (sb.length() > 0) {
+ sb.append(",");
+ }
+ sb.append(l.get(0));
}
}
- }
-
- String welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
- if (welcomeBanner != null) {
- buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
- buffer.putString(welcomeBanner);
- buffer.putString("en");
+ buffer.putString(sb.toString());
+ buffer.putByte((byte) 1);
writePacket(buffer);
}
- buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_SUCCESS, 0);
- writePacket(buffer);
- setState(State.Running);
- this.authed = true;
- this.username = username;
- unscheduleAuthTimer();
- scheduleIdleTimer();
- log.info("Session {}@{} authenticated", getUsername(), getIoSession().getRemoteAddress());
+ if (currentAuth != null) {
+ currentAuth.destroy();
+ currentAuth = null;
+ }
} else {
+ log.debug("Authentication failed");
+
buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_FAILURE, 0);
- NamedFactory.Utils.remove(userAuthFactories, "none"); // 'none' MUST NOT be listed
- buffer.putString(NamedFactory.Utils.getNames(userAuthFactories));
- buffer.putByte((byte) 0);
+ StringBuilder sb = new StringBuilder();
+ for (List<String> l : authMethods) {
+ if (!l.isEmpty()) {
+ String m = l.get(0);
+ if (!"none".equals(m)) {
+ if (sb.length() > 0) {
+ sb.append(",");
+ }
+ sb.append(l.get(0));
+ }
+ }
+ }
+ buffer.putString(sb.toString());
+ buffer.putByte((byte) 1);
writePacket(buffer);
+
+ if (currentAuth != null) {
+ currentAuth.destroy();
+ currentAuth = null;
+ }
}
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a49dee37/sshd-core/src/test/java/org/apache/sshd/AuthenticationTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/AuthenticationTest.java b/sshd-core/src/test/java/org/apache/sshd/AuthenticationTest.java
new file mode 100644
index 0000000..67b5626
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/AuthenticationTest.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.Logger;
+import com.jcraft.jsch.UserInfo;
+import org.apache.mina.core.filterchain.IoFilterChain;
+import org.apache.mina.core.service.IoProcessor;
+import org.apache.mina.core.service.IoService;
+import org.apache.mina.core.service.TransportMetadata;
+import org.apache.mina.core.session.AbstractIoSession;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
+import org.apache.mina.transport.vmpipe.VmPipeAcceptor;
+import org.apache.mina.transport.vmpipe.VmPipeAddress;
+import org.apache.mina.transport.vmpipe.VmPipeConnector;
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Session;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.server.UserAuth;
+import org.apache.sshd.server.auth.UserAuthPassword;
+import org.apache.sshd.server.auth.UserAuthPublicKey;
+import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.server.session.SessionFactory;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.BogusPublickeyAuthenticator;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.ServerSocket;
+import java.net.SocketAddress;
+import java.security.KeyPair;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class AuthenticationTest {
+
+ private static final String WELCOME = "Welcome to SSHD";
+
+ private SshServer sshd;
+ private int port;
+
+ @Before
+ public void setUp() throws Exception {
+ ServerSocket s = new ServerSocket(0);
+ port = s.getLocalPort();
+ s.close();
+
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setPort(port);
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+ sshd.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());
+ sshd.setUserAuthFactories(Arrays.asList(
+ new UserAuthDummy.Factory(), new UserAuthPassword.Factory(), new UserAuthPublicKey.Factory()
+ ));
+ sshd.getProperties().put(SshServer.WELCOME_BANNER, WELCOME);
+ sshd.getProperties().put(SshServer.AUTH_METHODS, "publickey,password publickey,dummy");
+ sshd.setSessionFactory(new SessionFactory() {
+ @Override
+ protected AbstractSession doCreateSession(IoSession ioSession) throws Exception {
+ return new TestSession(server, ioSession);
+ }
+ });
+ sshd.start();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sshd != null) {
+ sshd.stop(true);
+ Thread.sleep(50);
+ }
+ }
+
+ @Test
+ public void testChangeUser() throws Exception {
+ SshClient client = SshClient.setUpDefaultClient();
+ client.start();
+ ClientSession s = client.connect("localhost", port).await().getSession();
+ s.waitFor(ClientSession.CLOSED | ClientSession.WAIT_AUTH, 0);
+
+ assertFalse(s.authPassword("user1", "the-password").await().isSuccess());
+ assertFalse(s.authPassword("user2", "the-password").await().isSuccess());
+
+ assertEquals(ClientSession.CLOSED, s.waitFor(ClientSession.CLOSED, 1000));
+ }
+
+ @Test
+ public void testAuth() throws Exception {
+ SshClient client = SshClient.setUpDefaultClient();
+ client.start();
+ ClientSession s = client.connect("localhost", port).await().getSession();
+ s.waitFor(ClientSession.CLOSED | ClientSession.WAIT_AUTH, 0);
+
+ assertFalse(s.authPassword("smx", "smx").await().isSuccess());
+
+ KeyPair pair = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
+ assertFalse(s.authPublicKey("smx", pair).await().isSuccess());
+
+ assertTrue(s.authPassword("smx", "smx").await().isSuccess());
+
+ s.close(true);
+ client.stop();
+ }
+
+ public static class TestSession extends ServerSession {
+ public TestSession(FactoryManager server, IoSession ioSession) throws Exception {
+ super(server, ioSession);
+ }
+ public void setState(State state) {
+ super.setState(state);
+ }
+ public void handleMessage(Buffer buffer) throws Exception {
+ super.handleMessage(buffer);
+ }
+ }
+
+ public static class UserAuthDummy implements UserAuth {
+ public static class Factory implements NamedFactory<UserAuth> {
+ public String getName() {
+ return "dummy";
+ }
+ public UserAuth create() {
+ return new UserAuthDummy();
+ }
+ }
+ public Boolean auth(ServerSession session, String username, String service, Buffer buffer) throws Exception {
+ return Boolean.TRUE;
+ }
+ }
+}
[2/4] git commit: Code formatting
Posted by gn...@apache.org.
Code formatting
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/34098dac
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/34098dac
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/34098dac
Branch: refs/heads/master
Commit: 34098dac637f452f8a14ef19cc55511b6d261924
Parents: 5bb8366
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 17 09:03:35 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 17 09:03:35 2013 +0200
----------------------------------------------------------------------
.../apache/sshd/server/HandshakingUserAuth.java | 96 ++--
.../sshd/server/auth/gss/CredentialHelper.java | 162 +++---
.../sshd/server/auth/gss/GSSAuthenticator.java | 180 +++---
.../sshd/server/auth/gss/UserAuthGSS.java | 550 +++++++++----------
.../sshd/server/session/ServerSession.java | 106 ++--
5 files changed, 539 insertions(+), 555 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
index 485e00f..625f7ba 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/HandshakingUserAuth.java
@@ -24,57 +24,55 @@ import org.apache.sshd.server.session.ServerSession;
/**
* Extension of UserAuth for use with methods which require handshakes, such as gssapi-with-mic.
- *
+ *
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public interface HandshakingUserAuth extends UserAuth {
-
- /**
- * Set the service name from the original request. This may be required for MIC verification later.
- *
- * @param service The service name
- */
-
- void setServiceName(String service);
-
- /**
- * Check whether a particular message is handled here.
- *
- * @param msg The message
- *
- * @return <code>true</code> if the message is handled
- */
-
- boolean handles(SshConstants.Message msg);
-
- /**
- * Handle another step in the authentication process.
- *
- * @param session the current ssh session
- * @param msg The message type
- * @param buffer the request buffer containing parameters specific to this request
- * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
- * is not finished yet
- * @throws Exception if the authentication fails
- */
-
- Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception;
-
- /**
- * Get a user name which has been derived from the handshaking process, or the intial name if
- * nothing has been found.
- *
- * @return The user name
- *
- * @throws Exception if the request fails
- */
-
- String getUserName() throws Exception;
-
- /**
- * Free any system resources used by the module.
- */
-
- void destroy();
+
+ /**
+ * Set the service name from the original request. This may be required for MIC verification later.
+ *
+ * @param service The service name
+ */
+
+ void setServiceName(String service);
+
+ /**
+ * Check whether a particular message is handled here.
+ *
+ * @param msg The message
+ * @return <code>true</code> if the message is handled
+ */
+
+ boolean handles(SshConstants.Message msg);
+
+ /**
+ * Handle another step in the authentication process.
+ *
+ * @param session the current ssh session
+ * @param msg The message type
+ * @param buffer the request buffer containing parameters specific to this request
+ * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
+ * is not finished yet
+ * @throws Exception if the authentication fails
+ */
+
+ Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception;
+
+ /**
+ * Get a user name which has been derived from the handshaking process, or the intial name if
+ * nothing has been found.
+ *
+ * @return The user name
+ * @throws Exception if the request fails
+ */
+
+ String getUserName() throws Exception;
+
+ /**
+ * Free any system resources used by the module.
+ */
+
+ void destroy();
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java
index 91cca9f..37ce5d3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/CredentialHelper.java
@@ -39,94 +39,92 @@ import org.ietf.jgss.GSSManager;
*/
public class CredentialHelper {
-
- public static GSSCredential creds(GSSManager mgr, String spn, String keytab) throws LoginException, GSSException {
- LoginContext lc = new LoginContext("x", null, null, new FixedLoginConfiguration(spn, keytab));
-
- lc.login();
-
- try {
- return (GSSCredential) Subject.doAs(lc.getSubject(), new G(mgr));
- } catch (PrivilegedActionException e) {
- throw (GSSException) e.getCause();
- }
- }
-
- /**
- * A login configuration which is defined from code.
- *
- * @author Richard Evans
- */
-
- private static class FixedLoginConfiguration extends Configuration {
-
- private AppConfigurationEntry entry;
-
- /**
- * Constructor.
- */
-
- private FixedLoginConfiguration(String spn, String keytab) {
- Map<String, String> parms = new HashMap<String, String>();
-
- parms.put("isInitiator", "false");
- parms.put("principal", spn);
- parms.put("useKeyTab", "true");
- parms.put("storeKey", "true");
-
- if (keytab != null) {
- parms.put("keyTab", keytab);
- }
-
- entry = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, parms);
- }
-
- /**
- * Get the configuration entries for a name.
- *
- * @param name The name
- *
- * @return The entries, or <code>null</code> if the name is not known
- */
-
- public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
- return new AppConfigurationEntry [] { entry };
- }
- /**
- * Refresh the configuration. Nothing to do here.
- */
-
- public void refresh() {
+ public static GSSCredential creds(GSSManager mgr, String spn, String keytab) throws LoginException, GSSException {
+ LoginContext lc = new LoginContext("x", null, null, new FixedLoginConfiguration(spn, keytab));
+
+ lc.login();
+
+ try {
+ return (GSSCredential) Subject.doAs(lc.getSubject(), new G(mgr));
+ } catch (PrivilegedActionException e) {
+ throw (GSSException) e.getCause();
+ }
}
- }
-
- /**
- * Privileged action which runs as the subject to get the credentials.
- */
-
- private static final class G implements PrivilegedExceptionAction<GSSCredential> {
-
- private GSSManager mgr;
-
+
/**
- * @param mgr The existing GSS manager
+ * A login configuration which is defined from code.
+ *
+ * @author Richard Evans
*/
-
- private G(GSSManager mgr) {
- this.mgr = mgr;
+
+ private static class FixedLoginConfiguration extends Configuration {
+
+ private AppConfigurationEntry entry;
+
+ /**
+ * Constructor.
+ */
+
+ private FixedLoginConfiguration(String spn, String keytab) {
+ Map<String, String> parms = new HashMap<String, String>();
+
+ parms.put("isInitiator", "false");
+ parms.put("principal", spn);
+ parms.put("useKeyTab", "true");
+ parms.put("storeKey", "true");
+
+ if (keytab != null) {
+ parms.put("keyTab", keytab);
+ }
+
+ entry = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, parms);
+ }
+
+ /**
+ * Get the configuration entries for a name.
+ *
+ * @param name The name
+ * @return The entries, or <code>null</code> if the name is not known
+ */
+
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ return new AppConfigurationEntry[]{entry};
+ }
+
+ /**
+ * Refresh the configuration. Nothing to do here.
+ */
+
+ public void refresh() {
+ }
}
-
+
/**
- * Do the action.
- *
- * @return The new credentials
- *
- * @throws GSSException If an error occurred
+ * Privileged action which runs as the subject to get the credentials.
*/
-
- public GSSCredential run() throws GSSException {
- return mgr.createCredential(null, GSSCredential.INDEFINITE_LIFETIME, UserAuthGSS.KRB5_MECH, GSSCredential.ACCEPT_ONLY);
+
+ private static final class G implements PrivilegedExceptionAction<GSSCredential> {
+
+ private GSSManager mgr;
+
+ /**
+ * @param mgr The existing GSS manager
+ */
+
+ private G(GSSManager mgr) {
+ this.mgr = mgr;
+ }
+
+ /**
+ * Do the action.
+ *
+ * @return The new credentials
+ * @throws GSSException If an error occurred
+ */
+
+ public GSSCredential run() throws GSSException {
+ return mgr.createCredential(null, GSSCredential.INDEFINITE_LIFETIME, UserAuthGSS.KRB5_MECH, GSSCredential.ACCEPT_ONLY);
+ }
}
- }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java
index fd988b9..96ef66b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/GSSAuthenticator.java
@@ -31,101 +31,97 @@ import org.ietf.jgss.GSSManager;
/**
* Class providing basic GSS authentication services. Can be used as-is, but is often extended to provide environment
* specific implementations.
- *
+ *
* @author Richard Evans
*/
public class GSSAuthenticator {
-
- // Options:
- //
- // Service principal name: if unset, use host/hostname
-
- private String servicePrincipalName;
-
- // Location of Kerberos key table; if unset use default
-
- private String keytabFile;
-
- /**
- * Overridable method to get GSS manager suitable for current environment.
- *
- * @return A new manager
- */
-
- public GSSManager getGSSManager() {
- return GSSManager.getInstance();
- }
-
- /**
- * Overridable method to get GSS accept credential suitable for the current environment. The default
- * implementation uses a Kerberos key table.
- *
- * @param mgr The GSS manager
- *
- * @return The credential; if the result is <code>null</code> gssapi authentication fails immediately
- *
- * @throws UnknownHostException If the local host name could not be determined
- * @throws LoginException If the subject could not be found
- * @throws GSSException If the credential could not be obtained
- */
-
- public GSSCredential getGSSCredential(GSSManager mgr) throws UnknownHostException, LoginException, GSSException {
-
- String name = servicePrincipalName;
-
- if (name == null) {
- name = "host/" + InetAddress.getLocalHost().getCanonicalHostName();
+
+ // Options:
+ //
+ // Service principal name: if unset, use host/hostname
+
+ private String servicePrincipalName;
+
+ // Location of Kerberos key table; if unset use default
+
+ private String keytabFile;
+
+ /**
+ * Overridable method to get GSS manager suitable for current environment.
+ *
+ * @return A new manager
+ */
+
+ public GSSManager getGSSManager() {
+ return GSSManager.getInstance();
+ }
+
+ /**
+ * Overridable method to get GSS accept credential suitable for the current environment. The default
+ * implementation uses a Kerberos key table.
+ *
+ * @param mgr The GSS manager
+ * @return The credential; if the result is <code>null</code> gssapi authentication fails immediately
+ * @throws UnknownHostException If the local host name could not be determined
+ * @throws LoginException If the subject could not be found
+ * @throws GSSException If the credential could not be obtained
+ */
+
+ public GSSCredential getGSSCredential(GSSManager mgr) throws UnknownHostException, LoginException, GSSException {
+
+ String name = servicePrincipalName;
+
+ if (name == null) {
+ name = "host/" + InetAddress.getLocalHost().getCanonicalHostName();
+ }
+
+ return CredentialHelper.creds(mgr, name, keytabFile);
+ }
+
+ /**
+ * Validate the user name passed in the initial SSH_MSG_USERAUTH_REQUEST message. This is sort of mandated by RFC 4462, but it
+ * may be more useful to wait for the GSS negotiation to complete. The default implementation here always succeeds.
+ *
+ * @param session The current session
+ * @param user The user name from the initial request
+ * @return <code>true</code> if the user is valid, <code>false</code> if invalid
+ */
+
+ public boolean validateInitialUser(ServerSession session, String user) {
+ return true;
+ }
+
+ /**
+ * Validate the source identity obtained from the context after negotiation is complete.
+ * The default implementation here always succeeds.
+ *
+ * @param session The current session
+ * @param identity The identity from the GSS context
+ * @return <code>true</code> if the identity is valid, <code>false</code> if invalid
+ */
+
+ public boolean validateIdentity(ServerSession session, String identity) {
+ return true;
+ }
+
+ /**
+ * Set the service principal name to be used. The default is host/hostname.
+ *
+ * @param servicePrincipalName The principal name
+ */
+
+ public void setServicePrincipalName(String servicePrincipalName) {
+ this.servicePrincipalName = servicePrincipalName;
+ }
+
+ /**
+ * Set the location of the Kerberos keytab. The default is defined by the JRE.
+ *
+ * @param keytabFile The location of the keytab
+ */
+
+ public void setKeytabFile(String keytabFile) {
+ this.keytabFile = keytabFile;
}
-
- return CredentialHelper.creds(mgr, name, keytabFile);
- }
-
- /**
- * Validate the user name passed in the initial SSH_MSG_USERAUTH_REQUEST message. This is sort of mandated by RFC 4462, but it
- * may be more useful to wait for the GSS negotiation to complete. The default implementation here always succeeds.
- *
- * @param session The current session
- * @param user The user name from the initial request
- *
- * @return <code>true</code> if the user is valid, <code>false</code> if invalid
- */
-
- public boolean validateInitialUser(ServerSession session, String user) {
- return true;
- }
-
- /**
- * Validate the source identity obtained from the context after negotiation is complete.
- * The default implementation here always succeeds.
- *
- * @param session The current session
- * @param identity The identity from the GSS context
- *
- * @return <code>true</code> if the identity is valid, <code>false</code> if invalid
- */
-
- public boolean validateIdentity(ServerSession session, String identity) {
- return true;
- }
-
- /**
- * Set the service principal name to be used. The default is host/hostname.
- *
- * @param servicePrincipalName The principal name
- */
-
- public void setServicePrincipalName(String servicePrincipalName) {
- this.servicePrincipalName = servicePrincipalName;
- }
-
- /**
- * Set the location of the Kerberos keytab. The default is defined by the JRE.
- *
- * @param keytabFile The location of the keytab
- */
-
- public void setKeytabFile(String keytabFile) {
- this.keytabFile = keytabFile;
- }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
index c2518dc..afcca3a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/gss/UserAuthGSS.java
@@ -36,304 +36,296 @@ import org.slf4j.LoggerFactory;
/**
* Prototype user authentication handling gssapi-with-mic. Implements <code>HandshakingUserAuth</code> because
* the process involves several steps.
- *
+ * <p/>
* Several methods are available for overriding in specific circumstances.
*/
public class UserAuthGSS implements HandshakingUserAuth {
-
- // Oids for the Kerberos 5 mechanism and principal
-
- public static final Oid KRB5_MECH = createOID("1.2.840.113554.1.2.2");
- public static final Oid KRB5_NT_PRINCIPAL = createOID("1.2.840.113554.1.2.2.1");
-
- // Options:
- //
- // Service principal name: if unset, use host/hostname
-
- private String servicePrincipalName;
-
- // Location of Kerberos key table; if unset use default
-
- private String keytabFile;
-
- // The on-going GSS context.
-
- private GSSContext ctxt;
-
- // Accept credentials
-
- private GSSCredential creds;
-
- // Original request data
-
- private String user;
- private String service;
-
- // Identity from context
-
- private String identity;
-
- // Logging
-
- private Logger log = LoggerFactory.getLogger(getClass());
-
- /**
- * Handle the first authentication step.
- *
- * @param sess The server session
- * @param user The user name from the request
- * @param buff The request buffer
- *
- * @return True or false if the authentication succeeded, or <code>null</code> to continue further
- *
- * @throws Exception If something went wrong
- */
-
- public Boolean auth(ServerSession sess, String user, Buffer buff) throws Exception {
- GSSAuthenticator auth = getAuthenticator(sess);
-
- this.user = user;
-
- // Get mechanism count from buffer and look for Kerberos 5.
-
- int num = buff.getInt();
-
- for (int i = 0; i < num; i++) {
- Oid oid = new Oid(buff.getBytes());
-
- if (oid.equals(KRB5_MECH)) {
- log.debug("UserAuthGSS: found Kerberos 5");
-
- // Validate initial user before proceeding
-
- if (!auth.validateInitialUser(sess, user)) {
- return Boolean.FALSE;
- }
- GSSManager mgr = auth.getGSSManager();
- GSSCredential creds = auth.getGSSCredential(mgr);
-
- if (creds == null) {
- return Boolean.FALSE;
+ // Oids for the Kerberos 5 mechanism and principal
+
+ public static final Oid KRB5_MECH = createOID("1.2.840.113554.1.2.2");
+ public static final Oid KRB5_NT_PRINCIPAL = createOID("1.2.840.113554.1.2.2.1");
+
+ // Options:
+ //
+ // Service principal name: if unset, use host/hostname
+
+ private String servicePrincipalName;
+
+ // Location of Kerberos key table; if unset use default
+
+ private String keytabFile;
+
+ // The on-going GSS context.
+
+ private GSSContext ctxt;
+
+ // Accept credentials
+
+ private GSSCredential creds;
+
+ // Original request data
+
+ private String user;
+ private String service;
+
+ // Identity from context
+
+ private String identity;
+
+ // Logging
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * Handle the first authentication step.
+ *
+ * @param sess The server session
+ * @param user The user name from the request
+ * @param buff The request buffer
+ * @return True or false if the authentication succeeded, or <code>null</code> to continue further
+ * @throws Exception If something went wrong
+ */
+
+ public Boolean auth(ServerSession sess, String user, Buffer buff) throws Exception {
+ GSSAuthenticator auth = getAuthenticator(sess);
+
+ this.user = user;
+
+ // Get mechanism count from buffer and look for Kerberos 5.
+
+ int num = buff.getInt();
+
+ for (int i = 0; i < num; i++) {
+ Oid oid = new Oid(buff.getBytes());
+
+ if (oid.equals(KRB5_MECH)) {
+ log.debug("UserAuthGSS: found Kerberos 5");
+
+ // Validate initial user before proceeding
+
+ if (!auth.validateInitialUser(sess, user)) {
+ return Boolean.FALSE;
+ }
+
+ GSSManager mgr = auth.getGSSManager();
+ GSSCredential creds = auth.getGSSCredential(mgr);
+
+ if (creds == null) {
+ return Boolean.FALSE;
+ }
+
+ ctxt = mgr.createContext(creds);
+
+ // Send the matching mechanism back to the client
+
+ Buffer b = sess.createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_INFO_REQUEST, 0);
+ byte[] out = oid.getDER();
+
+ b.putBytes(out);
+ sess.writePacket(b);
+
+ return null;
+ }
}
- ctxt = mgr.createContext(creds);
-
- // Send the matching mechanism back to the client
+ // No matching mechanism found
+
+ return Boolean.FALSE;
+ }
- Buffer b = sess.createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_INFO_REQUEST, 0);
- byte [] out = oid.getDER();
+ /**
+ * Set the service name from the original request. This may be required for MIC verification later.
+ *
+ * @param service The service name
+ */
- b.putBytes(out);
- sess.writePacket(b);
-
- return null;
- }
+ public void setServiceName(String service) {
+ this.service = service;
}
-
- // No matching mechanism found
-
- return Boolean.FALSE;
- }
-
- /**
- * Set the service name from the original request. This may be required for MIC verification later.
- *
- * @param service The service name
- */
-
- public void setServiceName(String service) {
- this.service = service;
- }
-
- /**
- * Check whether a particular message is handled here.
- *
- * @param msg The message
- *
- * @return <code>true</code> if the message is handled
- */
-
- public boolean handles(SshConstants.Message msg) {
- return msg == SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE || msg == SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC && ctxt.isEstablished();
- }
-
- /**
- * Handle another step in the authentication process.
- *
- * @param session the current ssh session
- * @param buffer the request buffer containing parameters specific to this request
- *
- * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
- * is not finished yet
- *
- * @throws Exception if the authentication fails
- */
-
- public Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception {
- GSSAuthenticator auth = getAuthenticator(session);
-
- log.debug("In krb5.next: msg = " + msg);
-
- // If the context is established, this must be a MIC message
-
- if (ctxt.isEstablished()) {
-
- if (msg != SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC) {
- return Boolean.FALSE;
- }
-
- // Make the MIC message so the token can be verified
-
- Buffer msgbuf = new Buffer();
-
- msgbuf.putString(session.getSessionId());
- msgbuf.putByte(SshConstants.Message.SSH_MSG_USERAUTH_REQUEST.toByte());
- msgbuf.putString(user.getBytes("UTF-8"));
- msgbuf.putString(service);
- msgbuf.putString("gssapi-with-mic");
-
- byte [] msgbytes = msgbuf.getCompactData();
- byte [] inmic = buffer.getBytes();
-
- try {
- ctxt.verifyMIC(inmic, 0, inmic.length, msgbytes, 0, msgbytes.length, new MessageProp(false));
- log.debug("MIC verified");
- return Boolean.TRUE;
- } catch (GSSException e) {
- log.info("GSS verification error: {}", e.toString());
- return Boolean.FALSE;
- }
-
- } else {
-
- // Not established - new token to process
-
- byte [] tok = buffer.getBytes();
- byte [] out = ctxt.acceptSecContext(tok, 0, tok.length);
- boolean established = ctxt.isEstablished();
-
- // Validate identity if context is now established
-
- if (established && identity == null) {
- identity = ctxt.getSrcName().toString();
- log.info("GSS identity is {}", identity);
-
- if (!auth.validateIdentity(session, identity)) {
- return Boolean.FALSE;
- }
- }
-
- // Send return token if necessary
-
- if (out != null && out.length > 0) {
- Buffer b = session.createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE, 0);
-
- b.putBytes(out);
- session.writePacket(b);
- return null;
- } else {
- return Boolean.valueOf(established);
- }
+
+ /**
+ * Check whether a particular message is handled here.
+ *
+ * @param msg The message
+ * @return <code>true</code> if the message is handled
+ */
+
+ public boolean handles(SshConstants.Message msg) {
+ return msg == SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE || msg == SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC && ctxt.isEstablished();
}
- }
-
- /**
- * Get a user name which has been derived from the handshaking process, or the initial name if
- * nothing has been found.
- *
- * @return The user name
- */
-
- public String getUserName() throws GSSException {
- return identity;
- }
-
- /**
- * Free any system resources used by the module.
- */
-
- public void destroy() {
- if (creds != null) {
- try {
- creds.dispose();
- } catch (GSSException e) {
- // ignore
- }
-
- if (ctxt != null) {
-
- try {
- ctxt.dispose();
- } catch (GSSException e) {
- // ignore
+
+ /**
+ * Handle another step in the authentication process.
+ *
+ * @param session the current ssh session
+ * @param buffer the request buffer containing parameters specific to this request
+ * @return <code>true</code> if the authentication succeeded, <code>false</code> if the authentication
+ * is not finished yet
+ * @throws Exception if the authentication fails
+ */
+
+ public Boolean next(ServerSession session, SshConstants.Message msg, Buffer buffer) throws Exception {
+ GSSAuthenticator auth = getAuthenticator(session);
+
+ log.debug("In krb5.next: msg = " + msg);
+
+ // If the context is established, this must be a MIC message
+
+ if (ctxt.isEstablished()) {
+
+ if (msg != SshConstants.Message.SSH_MSG_USERAUTH_GSSAPI_MIC) {
+ return Boolean.FALSE;
+ }
+
+ // Make the MIC message so the token can be verified
+
+ Buffer msgbuf = new Buffer();
+
+ msgbuf.putString(session.getSessionId());
+ msgbuf.putByte(SshConstants.Message.SSH_MSG_USERAUTH_REQUEST.toByte());
+ msgbuf.putString(user.getBytes("UTF-8"));
+ msgbuf.putString(service);
+ msgbuf.putString("gssapi-with-mic");
+
+ byte[] msgbytes = msgbuf.getCompactData();
+ byte[] inmic = buffer.getBytes();
+
+ try {
+ ctxt.verifyMIC(inmic, 0, inmic.length, msgbytes, 0, msgbytes.length, new MessageProp(false));
+ log.debug("MIC verified");
+ return Boolean.TRUE;
+ } catch (GSSException e) {
+ log.info("GSS verification error: {}", e.toString());
+ return Boolean.FALSE;
+ }
+
+ } else {
+
+ // Not established - new token to process
+
+ byte[] tok = buffer.getBytes();
+ byte[] out = ctxt.acceptSecContext(tok, 0, tok.length);
+ boolean established = ctxt.isEstablished();
+
+ // Validate identity if context is now established
+
+ if (established && identity == null) {
+ identity = ctxt.getSrcName().toString();
+ log.info("GSS identity is {}", identity);
+
+ if (!auth.validateIdentity(session, identity)) {
+ return Boolean.FALSE;
+ }
+ }
+
+ // Send return token if necessary
+
+ if (out != null && out.length > 0) {
+ Buffer b = session.createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_INFO_RESPONSE, 0);
+
+ b.putBytes(out);
+ session.writePacket(b);
+ return null;
+ } else {
+ return Boolean.valueOf(established);
+ }
}
- }
}
- }
-
- /**
- * Utility to get the configured GSS authenticator for the server, throwing an exception if none is available.
- *
- * @param session The current session
- *
- * @return The GSS authenticator
- *
- * @throws Exception If no GSS authenticator is defined
- */
-
- private GSSAuthenticator getAuthenticator(ServerSession session) throws Exception {
- GSSAuthenticator ga = session.getServerFactoryManager().getGSSAuthenticator();
-
- if (ga == null) {
- throw new Exception("No GSSAuthenticator configured");
- } else {
- return ga;
+
+ /**
+ * Get a user name which has been derived from the handshaking process, or the initial name if
+ * nothing has been found.
+ *
+ * @return The user name
+ */
+
+ public String getUserName() throws GSSException {
+ return identity;
+ }
+
+ /**
+ * Free any system resources used by the module.
+ */
+
+ public void destroy() {
+ if (creds != null) {
+ try {
+ creds.dispose();
+ } catch (GSSException e) {
+ // ignore
+ }
+
+ if (ctxt != null) {
+
+ try {
+ ctxt.dispose();
+ } catch (GSSException e) {
+ // ignore
+ }
+ }
+ }
}
- }
-
- /**
- * Utility to construct an Oid from a string, ignoring the annoying exception.
- *
- * @param rep The string form
- *
- * @return The Oid
- */
-
- private static Oid createOID(String rep) {
- try {
- return new Oid(rep);
- } catch (GSSException e) {
- // won't happen
- return null;
+
+ /**
+ * Utility to get the configured GSS authenticator for the server, throwing an exception if none is available.
+ *
+ * @param session The current session
+ * @return The GSS authenticator
+ * @throws Exception If no GSS authenticator is defined
+ */
+
+ private GSSAuthenticator getAuthenticator(ServerSession session) throws Exception {
+ GSSAuthenticator ga = session.getServerFactoryManager().getGSSAuthenticator();
+
+ if (ga == null) {
+ throw new Exception("No GSSAuthenticator configured");
+ } else {
+ return ga;
+ }
}
- }
-
- /**
- * Factory class.
- */
-
- public static class Factory implements NamedFactory<UserAuth> {
-
+
/**
- * Get the name of the authentication method.
- *
- * @return Tge name, always 'gssapi-with-mic' here.
+ * Utility to construct an Oid from a string, ignoring the annoying exception.
+ *
+ * @param rep The string form
+ * @return The Oid
*/
-
- public String getName() {
- return "gssapi-with-mic";
+
+ private static Oid createOID(String rep) {
+ try {
+ return new Oid(rep);
+ } catch (GSSException e) {
+ // won't happen
+ return null;
+ }
}
-
+
/**
- * Create a new authenticator instance.
- *
- * @return The instance
+ * Factory class.
*/
-
- public UserAuth create() {
- return new UserAuthGSS();
+
+ public static class Factory implements NamedFactory<UserAuth> {
+
+ /**
+ * Get the name of the authentication method.
+ *
+ * @return Tge name, always 'gssapi-with-mic' here.
+ */
+
+ public String getName() {
+ return "gssapi-with-mic";
+ }
+
+ /**
+ * Create a new authenticator instance.
+ *
+ * @return The instance
+ */
+
+ public UserAuth create() {
+ return new UserAuthGSS();
+ }
}
- }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/34098dac/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index f095ed7..d87fdd4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -364,69 +364,69 @@ public class ServerSession extends AbstractSession {
if (nbAuthRequests++ > maxAuthRequests) {
throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Too may authentication failures");
}
-
- Boolean authed = null;
- String username = null;
+
+ Boolean authed = null;
+ String username = null;
if (cmd == SshConstants.Message.SSH_MSG_USERAUTH_REQUEST) {
- username = buffer.getString();
-
- String svcName = buffer.getString();
- String method = buffer.getString();
-
- log.debug("Authenticating user '{}' with method '{}'", username, method);
- NamedFactory<UserAuth> factory = NamedFactory.Utils.get(userAuthFactories, method);
- if (factory != null) {
- UserAuth auth = factory.create();
- try {
- authed = auth.auth(this, username, buffer);
- if (authed == null) {
- // authentication is still ongoing
- log.debug("Authentication not finished");
-
- if (auth instanceof HandshakingUserAuth) {
- currentAuth = (HandshakingUserAuth) auth;
-
- // GSSAPI needs the user name and service to verify the MIC
-
- currentAuth.setServiceName(svcName);
+ username = buffer.getString();
+
+ String svcName = buffer.getString();
+ String method = buffer.getString();
+
+ log.debug("Authenticating user '{}' with method '{}'", username, method);
+ NamedFactory<UserAuth> factory = NamedFactory.Utils.get(userAuthFactories, method);
+ if (factory != null) {
+ UserAuth auth = factory.create();
+ try {
+ authed = auth.auth(this, username, buffer);
+ if (authed == null) {
+ // authentication is still ongoing
+ log.debug("Authentication not finished");
+
+ if (auth instanceof HandshakingUserAuth) {
+ currentAuth = (HandshakingUserAuth) auth;
+
+ // GSSAPI needs the user name and service to verify the MIC
+
+ currentAuth.setServiceName(svcName);
+ }
+ return;
+ } else {
+ log.debug(authed ? "Authentication succeeded" : "Authentication failed");
+ }
+ } catch (Exception e) {
+ // Continue
+ authed = false;
+ log.debug("Authentication failed: {}", e.getMessage());
}
- return;
- } else {
- log.debug(authed ? "Authentication succeeded" : "Authentication failed");
- }
- } catch (Exception e) {
- // Continue
- authed = false;
- log.debug("Authentication failed: {}", e.getMessage());
+
+ } else {
+ log.debug("Unsupported authentication method '{}'", method);
}
-
- } else {
- log.debug("Unsupported authentication method '{}'", method);
- }
} else {
- try {
- authed = currentAuth.next(this, cmd, buffer);
-
- if (authed == null) {
- // authentication is still ongoing
- log.debug("Authentication still not finished");
- return;
- } else if (authed.booleanValue()) {
- username = currentAuth.getUserName();
+ try {
+ authed = currentAuth.next(this, cmd, buffer);
+
+ if (authed == null) {
+ // authentication is still ongoing
+ log.debug("Authentication still not finished");
+ return;
+ } else if (authed.booleanValue()) {
+ username = currentAuth.getUserName();
+ }
+ } catch (Exception e) {
+ // failed
+ authed = false;
+ log.debug("Authentication next failed: {}", e.getMessage());
}
- } catch (Exception e) {
- // failed
- authed = false;
- log.debug("Authentication next failed: {}", e.getMessage());
- }
}
// No more handshakes now - clean up if necessary
-
+
if (currentAuth != null) {
- currentAuth.destroy();
- currentAuth = null;
+ currentAuth.destroy();
+ currentAuth = null;
}
if (authed != null && authed) {
Re: [3/4] git commit: [SSHD-195] Client side welcome banner support
Posted by sebb <se...@gmail.com>.
On 17 July 2013 15:32, <gn...@apache.org> wrote:
> [SSHD-195] Client side welcome banner support
>
> Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
> Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/1937ee8e
> Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/1937ee8e
> Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/1937ee8e
>
> Branch: refs/heads/master
> Commit: 1937ee8ebbebb2886ba5bcab0705a80e57a8f286
> Parents: 34098da
> Author: Guillaume Nodet <gn...@apache.org>
> Authored: Wed Jul 17 10:28:59 2013 +0200
> Committer: Guillaume Nodet <gn...@apache.org>
> Committed: Wed Jul 17 10:28:59 2013 +0200
>
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
> index d87fdd4..4582519 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
> @@ -447,7 +447,7 @@ public class ServerSession extends AbstractSession {
> if (welcomeBanner != null) {
> buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
> buffer.putString(welcomeBanner);
> - buffer.putString("\n");
> + buffer.putString("en");
Huh?
[3/4] git commit: [SSHD-195] Client side welcome banner support
Posted by gn...@apache.org.
[SSHD-195] Client side welcome banner support
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/1937ee8e
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/1937ee8e
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/1937ee8e
Branch: refs/heads/master
Commit: 1937ee8ebbebb2886ba5bcab0705a80e57a8f286
Parents: 34098da
Author: Guillaume Nodet <gn...@apache.org>
Authored: Wed Jul 17 10:28:59 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Wed Jul 17 10:28:59 2013 +0200
----------------------------------------------------------------------
.../main/java/org/apache/sshd/SshClient.java | 10 +++
.../sshd/client/ClientFactoryManager.java | 7 ++
.../org/apache/sshd/client/UserInteraction.java | 35 +++++++++
.../sshd/client/session/ClientSessionImpl.java | 43 +++++++----
.../sshd/server/session/ServerSession.java | 2 +-
.../java/org/apache/sshd/WelcomeBannerTest.java | 79 ++++++++++++++++++++
6 files changed, 159 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
index c0b8167..336145f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
@@ -40,6 +40,7 @@ import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.SessionFactory;
+import org.apache.sshd.client.UserInteraction;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.future.ConnectFuture;
import org.apache.sshd.client.future.DefaultConnectFuture;
@@ -134,6 +135,7 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
protected IoConnector connector;
protected SessionFactory sessionFactory;
+ protected UserInteraction userInteraction;
private ServerKeyVerifier serverKeyVerifier;
@@ -156,6 +158,14 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
this.serverKeyVerifier = serverKeyVerifier;
}
+ public UserInteraction getUserInteraction() {
+ return userInteraction;
+ }
+
+ public void setUserInteraction(UserInteraction userInteraction) {
+ this.userInteraction = userInteraction;
+ }
+
protected void checkConfig() {
if (getKeyExchangeFactories() == null) {
throw new IllegalArgumentException("KeyExchangeFactories not set");
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
index 3812b8c..f83d618 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
@@ -54,4 +54,11 @@ public interface ClientFactoryManager extends FactoryManager {
* @return A <code>TcpipForwarderFactory</code>
*/
TcpipForwarderFactory getTcpipForwarderFactory();
+
+ /**
+ * Retrieve the UserInteraction object to communicate with the user.
+ *
+ * @return A <code>UserInteraction</code> or <code>null</code>
+ */
+ UserInteraction getUserInteraction();
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/client/UserInteraction.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/UserInteraction.java b/sshd-core/src/main/java/org/apache/sshd/client/UserInteraction.java
new file mode 100644
index 0000000..72dbca5
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/UserInteraction.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.client;
+
+/**
+ * Interface used by the ssh client to communicate with the end user.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface UserInteraction {
+
+ /**
+ * Displays the welcome banner to the user.
+ *
+ * @param banner the welcome banner
+ */
+ void welcome(String banner);
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index 35748ef..37f7175 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -30,6 +30,7 @@ import org.apache.sshd.ClientChannel;
import org.apache.sshd.ClientSession;
import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.client.UserInteraction;
import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.client.UserAuth;
import org.apache.sshd.client.auth.UserAuthAgent;
@@ -345,22 +346,32 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
if (userAuth == null) {
throw new IllegalStateException("State is userAuth, but no user auth pending!!!");
}
- buffer.rpos(buffer.rpos() - 1);
- switch (userAuth.next(buffer)) {
- case Success:
- authFuture.setAuthed(true);
- username = userAuth.getUsername();
- authed = true;
- setState(State.Running);
- startHeartBeat();
- break;
- case Failure:
- authFuture.setAuthed(false);
- userAuth = null;
- setState(State.WaitForAuth);
- break;
- case Continued:
- break;
+ if (cmd == SshConstants.Message.SSH_MSG_USERAUTH_BANNER) {
+ String welcome = buffer.getString();
+ String lang = buffer.getString();
+ log.debug("Welcome banner: " + welcome);
+ UserInteraction ui = getClientFactoryManager().getUserInteraction();
+ if (ui != null) {
+ ui.welcome(welcome);
+ }
+ } else {
+ buffer.rpos(buffer.rpos() - 1);
+ switch (userAuth.next(buffer)) {
+ case Success:
+ authFuture.setAuthed(true);
+ username = userAuth.getUsername();
+ authed = true;
+ setState(State.Running);
+ startHeartBeat();
+ break;
+ case Failure:
+ authFuture.setAuthed(false);
+ userAuth = null;
+ setState(State.WaitForAuth);
+ break;
+ case Continued:
+ break;
+ }
}
break;
case Running:
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index d87fdd4..4582519 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -447,7 +447,7 @@ public class ServerSession extends AbstractSession {
if (welcomeBanner != null) {
buffer = createBuffer(SshConstants.Message.SSH_MSG_USERAUTH_BANNER, 0);
buffer.putString(welcomeBanner);
- buffer.putString("\n");
+ buffer.putString("en");
writePacket(buffer);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1937ee8e/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java b/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
new file mode 100644
index 0000000..bb5a222
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/WelcomeBannerTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd;
+
+import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.util.BogusPasswordAuthenticator;
+import org.apache.sshd.util.BogusPublickeyAuthenticator;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.ServerSocket;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static junit.framework.Assert.assertEquals;
+
+public class WelcomeBannerTest {
+
+ private static final String WELCOME = "Welcome to SSHD";
+
+ private SshServer sshd;
+ private int port;
+
+ @Before
+ public void setUp() throws Exception {
+ ServerSocket s = new ServerSocket(0);
+ port = s.getLocalPort();
+ s.close();
+
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setPort(port);
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+ sshd.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());
+ sshd.getProperties().put(SshServer.WELCOME_BANNER, WELCOME);
+ sshd.start();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (sshd != null) {
+ sshd.stop(true);
+ Thread.sleep(50);
+ }
+ }
+
+ @Test
+ public void testBanner() throws Exception {
+ final AtomicReference<String> welcome = new AtomicReference<String>();
+ SshClient client = SshClient.setUpDefaultClient();
+ client.setUserInteraction(new UserInteraction() {
+ public void welcome(String banner) {
+ welcome.set(banner);
+ }
+ });
+ client.start();
+ ClientSession session = client.connect("localhost", port).await().getSession();
+ session.authPassword("smx", "smx").await().isSuccess();
+ assertEquals(WELCOME, welcome.get());
+ session.close(true);
+ }
+}