accueilLogicielsDéveloppement et Qualité LogicielsÉcosystème Java
 

Embarquer un serveur SFTP en Java

Utilisation d’Apache Mina SSHD pour embarquer un serveur SFTP dans un programme Java.


Introduction

Nous avons vu dans un précédent article comment embarquer un serveur FTP ou FTPS en Java.

Nous allons voir comment réaliser la même chose avec un serveur SFTP.

Note : il est important d’être conscient que SFTP est un protocole totalement différent de FTPS. SFTP est un protocole de transferts de fichiers au dessus de SSH. FTPS est un protocole de transferts de fichiers basé sur FTP avec une couche de sécurité SSL.

On peut utiliser pour cela le projet Apache SSHD (un sous projet de Apache Mina). Ce projet propose un serveur SFTP 100% Java pouvant tourner seul ou embarqué.

Cet article montre son utilisation dans le cas de tests unitaires. La totalité du code est à la fin de cet article.

Apache SSHD

Dépendances

Les dépendances utilisées pour ces tests sont (en plus de JUnit) : Apache SSHD, ainsi que Apache Commons VFS2 et Jsch (pour le client SFTP). Avec Maven, il suffit de déclarer les dépendances suivantes :

<dependency>
        <groupId>org.apache.sshd</groupId>
        <artifactId>sshd-core</artifactId>
        <version>0.7.0</version>
</dependency>
<dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-vfs2</artifactId>
        <version>2.0</version>
</dependency>
<dependency>
        <groupId>com.jcraft</groupId>
        <artifactId>jsch</artifactId>
        <version>0.1.48</version>
</dependency>

Utilisation

Il existe une méthode permettant de créer un serveur avec des paramètres par défaut. Il faut ensuite définir le port par défaut :

final SshServer sshServer = SshServer.setUpDefaultServer();
sshServer.setPort(port);

Ensuite, il faut donner au serveur SFTP la façon de gérer les clés du serveur. Il existe une méthode très pratique permettant de générer automatiquement des clés au démarrage :

sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());

Il faut également indiquer comment gérer l’authentification. Dans le cadre de cet exemple, on autorise tout le monde :

List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<NamedFactory<UserAuth>>();
userAuthFactories.add(new UserAuthNone.Factory());
sshServer.setUserAuthFactories(userAuthFactories);

On indique que l’on utilise SFTP :

sshServer.setCommandFactory(new ScpCommandFactory());
List<NamedFactory<Command>> namedFactoryList = new ArrayList<NamedFactory<Command>>();
namedFactoryList.add(new SftpSubsystem.Factory());
sshServer.setSubsystemFactories(namedFactoryList);

Un exemple de test simple, utilisant Apache Commons VFS2 comme client SFTP :

@Test
public void listFTPSFiles() throws InterruptedException, IOException {
        final SshServer sshServer = createSshServer(SFTP_PORT);
        sshServer.start();

        // Récupération d'un fichier avec Apache Commons VFS2
        final FileSystemOptions fileSystemOptions = new FileSystemOptions();

        // On désactive le StrictHostKeyChecking, car les clés du serveur changent
        // à chaque création du serveur dans notre cas
        SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fileSystemOptions, "no");

        final FileSystemManager fileSystemManager = VFS.getManager();
        final FileObject fileObject = fileSystemManager.resolveFile("sftp://bob:bob@localhost:" + SFTP_PORT + "/ReadMe.txt");

        sshServer.stop();

        assertTrue("La taille doit être non nulle", fileObject.getContent().getSize() > 0);
}

Code utilisé dans l’article

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.VFS;
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
import org.apache.sshd.SshServer;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.UserAuth;
import org.apache.sshd.server.auth.UserAuthNone;
import org.apache.sshd.server.command.ScpCommandFactory;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class EmbeddedSftpServerTest {
        private final int SFTP_PORT = 2221;
        @Test
        public void listFTPSFiles() throws InterruptedException, IOException {
                final SshServer sshServer = createSshServer(SFTP_PORT);
                sshServer.start();
                // Récupération d'un fichier avec Apache Commons VFS2
                final FileSystemOptions fileSystemOptions = new FileSystemOptions();
                // On désactive le StrictHostKeyChecking, car les clés du serveur changent
                // à chaque création du serveur dans notre cas
                SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fileSystemOptions, "no");
                final FileSystemManager fileSystemManager = VFS.getManager();
                final FileObject fileObject = fileSystemManager.resolveFile("sftp://bob:bob@localhost:" + SFTP_PORT + "/ReadMe.txt");
                sshServer.stop();
                assertTrue("La taille doit être non nulle", fileObject.getContent().getSize() > 0);
        }
        private SshServer createSshServer(int port) {
                final SshServer sshServer = SshServer.setUpDefaultServer();
                sshServer.setPort(port);
                // Les clés du serveur sont générées automatiquement à la volée
                sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
                // Tous les utilisateurs sont autorisés
                List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<NamedFactory<UserAuth>>();
                userAuthFactories.add(new UserAuthNone.Factory());
                sshServer.setUserAuthFactories(userAuthFactories);
                // On va utiliser le SFTP
                sshServer.setCommandFactory(new ScpCommandFactory());
                List<NamedFactory<Command>> namedFactoryList = new ArrayList<NamedFactory<Command>>();
                namedFactoryList.add(new SftpSubsystem.Factory());
                sshServer.setSubsystemFactories(namedFactoryList);
                return sshServer;
        }
}

 

Stéphane DERACO
Envoyer un courriel

 


ARESU
Direction des Systèmes d'Information du CNRS

358 rue P.-G. de Gennes
31676 LABEGE Cedex

Bâtiment 1,
1 Place Aristide Briand
92195 MEUDON Cedex



 

 

Direction des Systèmes d'Information

Pôle ARESU

Accueil Imprimer Plan du site Credits