fév 10

Travaillant sur des projets dans un environnement financier, beaucoup de transferts se font de manière sécurisée.

Parmi eux, on retrouve très souvent les transferts de fichiers, habituellement rencontrés sur le protocole FTP. Or le protocole FTP n’est absolument pas sécurisé (données et mots de passe qui transitent en clair sur le réseau).

Le choix opérationnel se porte très souvent sur SFTP.
SFTP (SSH File Transfer Protocol), n’est pas FTP exécuté sur SSH, mais plutôt un nouveau protocole conçu dès le départ par le groupe de travail IETF SECSH.
STFP est un protocole de communication fonctionnant au-dessus de SSH à ne pas confondre avec File Transfer Protocol over SSL, abrégé FTPS.

L’objectif de cet article est d’écrire un bout de code pour se connecter à un serveur SFTP, uploader un fichier et télécharger un fichier.
Nous allons bien évidemment écrire un test unitaire et pour cela nous allons utiliser un serveur SFTP embarqué en mémoire.

Le client : Jsch

Jsch est une implémentation 100% Java de SSH2.

Cette librairie va nous permettre de communiquer avec un serveur SFTP.
L’authentification avec ce type de serveur peut se faire de 2 façons (n’oubliez pas que SFTP est du SSH, on retrouve donc beaucoup de choses en commun) :

  • 1 login et 1 mot de passe.
  • 1 login et 1 clé privée (dont la clé publique est enregistrée sur le serveur auparavant).

Dans cet article, nous utiliserons l’authentification par login/password (pour sa simplicité d’implémentation).

Un serveur SFTP pour les développements locaux

Pour les développements, je vous suggère d’utiliser un petit serveur SFTP à lancer sur votre poste :
miniSFTPServer est un mini-serveur SFTP ultra-léger vous permettant de travailler en local.

Il suffit de le lancer, puis de configurer un port, un login, un mot de passe et un chemin root pour le serveur.

La connection SFTP

Maintenant que le serveur SFTP est up&running en local, nous pouvons rentrer dans le vif du sujet.

La connection au serveur se fait sans encombre :

jsch = new JSch();
session = jsch.getSession(login, server, port);

// Java 6 version
session.setPassword(password.getBytes(Charset.forName("ISO-8859-1")));
            
// Java 5 version
// session.setPassword(password.getBytes("ISO-8859-1"));

Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);

session.connect();

Il faut ensuite rajouter un com.jcraft.jsch.Channel de type “sftp” (qui est un com.jcraft.jsch.ChannelSftp une fois le channel accepté) :

// Initializing a channel
channel = session.openChannel("sftp");
channel.connect();
c = (ChannelSftp) channel;

L’upload de fichier

C’est encore tout simple : le Channel précédemment créé nous propose une méthode put :

c.put(sourceFile, destinationFile);

Il s’agit ici de la version prenant 2 Strings en paramètres. Cette méthode existe en une foultitude de déclinaisons, je vous invite à regarder la Javadoc pour coller à vos besoins.

Le téléchargement de fichier

Même chose que précédemment : le Channel propose une méthode get :

c.get(sourceFile, destinationFile);

La déconnection

Comme tout flux en Java, il est important de fermer le Channel puis la Session pour se déconnecter proprement !

Le test unitaire : Mina SSHD

Le projet Mina propose un sous-module très intéressant pour les tests unitaires de serveurs SFTP : SSHD.

Nous allons utiliser SSHD pour démarrer un serveur SFTP en mémoire qui nous servira à tester notre client SFTP écrit précédemment.

@Before

Dans une méthode setUp (annotée en @Before), nous allons démarrer un org.apache.sshd.SshServer:

@Before
public void setUp() throws IOException {
    // Init sftp server stuff
    sshd = SshServer.setUpDefaultServer();
    sshd.setPort(port);
    sshd.setPasswordAuthenticator(new MyPasswordAuthenticator());
    sshd.setPublickeyAuthenticator(new MyPublickeyAuthenticator());
    sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
    sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
    sshd.setCommandFactory(new ScpCommandFactory());

    sshd.start();
    ...
    ...
}

La méthode setUpDefaultServer() préconfigure automatiquement le SshServer.
Il ne reste qu’à rajouter le port d’écoute, implémenter un PasswordAuthenticator très simple, ainsi qu’un PublicKeyAuthenticator.

La partie touchy est la suivante : rajouter un ChannelSftp n’est pas trivial :

sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));

Une fois le serveur démarré, le test unitaire est très facile à écrire.

@After

N’oubliez pas d’éteindre le SshServer à la fin de l’exécution des tests unitaires :

sshd.stop();

Code complet

Vous pouvez retrouver tout ce code à peu près bien organisé, commenté avec des logs dans projet Maven :


https://github.com/jpbriend/sftp-example

3 Responses to “Se connecter à un serveur SFTP en Java”

  1. Davy F dit :

    Un article super! J’ai lu déjà quelques choses de SFTP par Jsch, mais je voudrais voir un test unitaire pour comprendre mieux comme cela marche… et voila, c’est ici. Merci!

  2. jak78 dit :

    Super article ! Je t’ai proposé, via une pull request, de faire en sorte que le serveur SSH embedded écoute sur un port libre qu’il trouve tout seul, au lieu du port 22 par défaut. Le port 22 n’est pas toujours libre, et surtout : il faudrait être root pour lancer les tests sous un système Unix.

  3. Merci pour la pull request :)
    C’est mergé !

Leave a Reply


Creative Commons License
Blog Infin-It par Infin-It est mis à disposition selon les termes de la licence Creative Commons Paternité-Pas d'Utilisation Commerciale 2.0 France.