mina-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Davis Ford <df...@axeda.com>
Subject RE: SFTP/SSHD passwordauthenticator test case
Date Wed, 14 Sep 2011 16:32:51 GMT
I guess attachments are not allowed on the mailing list, so I've pasted the code inline:

-------------------------------
SftpServer.java == BEGIN
-------------------------------
package com.example;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.sshd.SshServer;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.apache.sshd.util.EchoShellFactory;


public class SftpServer implements PasswordAuthenticator {

       private final ConcurrentMap<String, String> authMap = new ConcurrentHashMap<String,
String>();

       private final AtomicBoolean started = new AtomicBoolean(false);

       private SshServer sshd;

       @SuppressWarnings("unchecked")
       public SftpServer(int port, File privateKey) throws IOException {
              sshd = SshServer.setUpDefaultServer();
              sshd.setPort(port);
              sshd.setKeyPairProvider(new FileKeyPairProvider(new String[]{privateKey.getAbsolutePath()}));
              sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new
SftpSubsystem.Factory()));
              sshd.setShellFactory(new EchoShellFactory());

              // this class manages authentication
              sshd.setPasswordAuthenticator(this);
              sshd.start();
       }

       public void createSession(String username, String password) {
              authMap.put(username, password);
              System.err.println(String.format("CREATE-SESSION: SftpServer identity:%s, authMap
identity:%s, authMap:%s, user:%s, pass:%s",
                           System.identityHashCode(this), System.identityHashCode(authMap),
authMap, username, password));

       }

       public boolean authenticate(String username, String password,
                     ServerSession session) {
              System.err.println(String.format("AUTHENTICATE: SftpServer identity:%s, authMap
identity:%s, authMap:%s, user:%s, pass:%s",
                           System.identityHashCode(this), System.identityHashCode(authMap),
authMap, username, password));
              if(authMap.containsKey(username)) {
                     return authMap.get(username).equals(password);
              }
              return false;
       }

       public void start() throws Exception {
              if(!started.compareAndSet(false, true)) {
                     sshd.start();
                     started.set(true);
              }
       }

       public void stop() throws Exception {
              if(started.get()) {
                     sshd.stop();
              }
       }
}

-------------------------------
SftpServer.java == END
-------------------------------

-------------------------------
SftpServerTest.java == BEGIN
-------------------------------
package com.example;

import static org.junit.Assert.fail;

import java.io.File;
import java.net.ServerSocket;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.UserInfo;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Logger;

import com.jcraft.jsch.Session;

public class SftpServerTest {

       private SftpServer server;

       private static int port;

       private static File privateKey = new File("src/test/resources/hostkey.pem");

       private Session session;

       private String username = "foo";
       private String password = "bar";
       private String hostname = "localhost";

       @BeforeClass
       public static void beforeClass() {
              try {
                     ServerSocket s = new ServerSocket(0);
                     port = s.getLocalPort();
                     s.close();
                     System.err.println("port chosen is "+port);
              } catch(Exception e) {
                     fail("Test setup fails trying to reserve an unused port "+e.getMessage());
              }
              if(privateKey.exists() == false) {
                     fail("Test setup fails because private RSA key file does not exist "+privateKey.getAbsolutePath());
              }
       }

       @Before
       public void setUp() throws Exception {
              server = new SftpServer(port, privateKey );
       }

       @After
       public void tearDown() throws Exception {
              if(session != null) { session.disconnect(); }
              server.stop();
       }

       @Test
       public void testCreateSingleSession() throws Exception {
              server.createSession(username, password);
              session = getSession(username, password, hostname);
       }

       @Test
       public void testCreateMultipleSessions() throws Exception {
              server.createSession(username, password);
              session = getSession(username, password, hostname);

              String username2 = username+2;
              String password2 = password+2;

              server.createSession(username2, password2);
              session = getSession(username2, password2, hostname);

              String username3 = username+3;
              String password3 = password+3;

              server.createSession(username3, password3);
              session = getSession(username3, password3, hostname);
       }

       /**
        * Get a client session that we can use to SFTP upload files with
        * @return a client session that we can use to SFTP files
        * @throws JSchException
        */
       private Session getSession(String username, final String password, String hostname)
throws JSchException  {
              JSch sch = new JSch();
              JSch.setLogger(new Logger(){

                     public boolean isEnabled(int arg0) {
                           return true;
                     }

                     public void log(int i, String s) {
                           System.out.println("Log(jsch "+i+"):" + s);
                     }


              });
              Session session = sch.getSession(username, hostname, port);
              session.setUserInfo(new UserInfo() {

                     public String getPassphrase() {
                           System.err.println("getPassphrase called");
                           return null;
                     }

                     public String getPassword() {
                           return password;
                     }

                     public boolean promptPassphrase(String s) {
                           System.err.println("promptPassphrase: "+s);
                           return false;
                     }

                     public boolean promptPassword(String s) {
                           System.err.println("promptPassword: "+s);
                           return true;
                     }

                     public boolean promptYesNo(String s) {
                           System.err.println("promptYesNo: "+s);
                           return true;
                     }

                     public void showMessage(String s) {
                           System.err.println("showMessage: "+s);
                     }

                     });
              session.connect();
              return session;
       }

}

-------------------------------
SftpServerTest.java == END
-------------------------------


From: Davis Ford [mailto:dford@axeda.com]
Sent: Wednesday, September 14, 2011 12:29 PM
To: users@mina.apache.org
Subject: SFTP/SSHD passwordauthenticator test case

Here's a follow up to my last email with a demo class / test case that illustrates the failure.

Add this code to the apache-sshd/sshd-core project under src/test/java/com/example

When you run the test the first case passes.  It spins up a new Sshd/SFTP server and connects
to it with the JSch client, and authenticates just fine with the user/pass obtained via the
ConcurrentHashMap.

The second test case fails.  It tries to connect multiple sessions with different user/pass
combos.  You'll see the following printed on system.err.println =>

First, we create a new session for foo=bar:
CREATE-SESSION: SftpServer identity:1190000432, authMap identity:822056113, authMap:{foo=bar},
user:foo, pass:bar
Then we authenticate -- works ok, you'll see foo=bar is in the map
AUTHENTICATE: SftpServer identity:1526115339, authMap identity:2023306452, authMap:{foo=bar},
user:foo, pass:bar
Now, we create a new session for foo2=bar2, note that it prints the contents of the map after
this call and it contains foo2=bar2
CREATE-SESSION: SftpServer identity:1190000432, authMap identity:822056113, authMap:{foo2=bar2,
foo=bar}, user:foo2, pass:bar2
Then we try to authenticate, but it fails.  foo2=bar2 is not in the map, and the identity
hashcode is different.
AUTHENTICATE: SftpServer identity:1526115339, authMap identity:2023306452, authMap:{foo=bar},
user:foo2, pass:bar2

Note that the identity hashcodes change between calls to createSession( ) in the test, and
authenticate( ) coming in from apache-sshd.  If you look at the code, you'll see that I don't
manipulate the ConcurrentMap anywhere in the code or the test case other than adding an entry
to it, and it is a private final instance variable.

So, why doesn't this work?  Something in the mina code is using a stale instance of the SftpServer.java
class it seems?

Any ideas?

Regards,
Davis

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message