Gestion des mots de passe

Cette page a été rédigée il y a fort fort longtemps, et n'a pas tellement été mise à jour.

 

Vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise page. Moi, si je devais résumer mon wiki aujourd'hui avec vous, je dirais que c'est d'abord des rencontres. Des gens qui m'ont tendu la main, peut-être à un moment où je ne pouvais pas, où j'étais seul chez moi. Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destinée... Parce que quand on a le goût de la chose, quand on a le goût de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face je dirais, le miroir qui vous aide à avancer. Alors ça n'est pas mon cas, comme je disais là, puisque moi au contraire, j'ai pu ; et je dis merci au wiki, je lui dis merci, je chante le wiki, je danse le wiki... je ne suis qu'amour ! Et finalement, quand des gens me disent « Mais comment fais-tu pour avoir cette humanité ? », je leur réponds très simplement que c'est ce goût de l'amour, ce goût donc qui m'a poussé aujourd'hui à entreprendre une construction logicielle... mais demain qui sait ? Peut-être simplement à me mettre au service de la communauté, à faire le don, le don de soi.

L’objectif de cet article est d’exposer les réponses que j’ai trouvée à certains problèmes de configuration du service d’authentification de Jonas. Pour les principes généraux de cette configuration, je renverrais le lecteur vers la documementation de Jonas.

jonas-realm.xml

Ce fichier sert à spécifier les techniques d’authentification utilisées par les applications déployées dans Jonas. Ces techniques peuvent être de plusieurs natures : stockage des users / passwords / roles dans une base de données, dans un annuaire LDAP, dans un fichier texte,…​

Dans l’exemple fourni, l’authentification se fait via un memoryrealm ; plusieurs exemples sont donnés en commentaire, en particulier un ldaprealm et un dsrealm.

Memory Realm

Le Memory Realm fourni est utilisé en particulier pour l’application d’administration, qui requiert le rôle jonas-admin. En étudiant rapidement ce realm, on constate que les utilisateurs tomcat et jadmin ont directement ce rôle, et que l’utilisateur jonas a aussi ce rôle, de par son appartenance au groupe jonas.

Il faut donc en conclure qu’il faut faire le ménage dans ces utilisateurs, avant toute mise en production, ou, au moins, changer les mots de passe. Encore faut-il savoir enregistrer correctement les mots de passe ; si vous souhaitez les écrire en clair, il n’y a aucun problème, mais si vous préférez les formats MD5 ou SHA, quelques problèmes apparaissent…​

Chiffrement des mots de passe

La documentation de Jonas nous indique juste qu’il est possible de stocker les mots de passe chiffrés en MD5 ou SHA. Le fichier jonas-realm.xml nous fourni un exemple de chaque chiffrement, pour le même mot de passe (jonas).

 <user name="jadmin" password="{MD5}nF3dVBB3NPfRgzWlJFwoaw==" roles="jonas-admin" />
 <user name="jonas" password="SHA:NaLG+uYfgHeqth+qQBlyKr8FCTw=" groups="jonas" />

En essayant d’appliquer une digestion MD5 ou SHA sur le texte "jonas", on obtient les résultats suivants :

 ~$ echo jonas | md5sum
 ~$ 5314232b04d20b370a37a6b784276635

 ~$ echo jonas | sha1sum
 ~$ b436e3b7cca6ca173669b9b17ca7338623712c4a

Il apparait clairement que les résultats ne corresopondent pas à l’exemple…​

Chiffrement SHA avec htpasswd

Pour chiffrer un mot de passe en SHA, il est possible d’utiliser la commande htpasswd, utiliser pour les mots de passe d’Apache HTTP Server.

 ~$ htpasswd -nbs ""  jonas
 ~$ :{SHA}NaLG+uYfgHeqth+qQBlyKr8FCTw=

La documentation de Apache précise que cette commande utilise SHA1 (sur 160 bits) avec un encodage base64.

Chiffrement MD5

La commande htpasswd ne fonctionne pas pour la digestion MD5 car l’algorithme utilisé par Apache n’est pas standard. Il a donc fallu approfondir les recherches.

Par analogie avec le traitement par SHA, j’ai essayé de combiner MD5 avec un encodage base64, en utilisant md5sum, ce qui n’a pas donné de résultat plus satisfaisant.

 ~$ echo 5314232b04d20b370a37a6b784276635 | base64
 ~$ NTMxNDIzMmIwNGQyMGIzNzBhMzdhNmI3ODQyNzY2MzUK

Ma première erreur a été d’utiliser simplement la commande echo ; en effet, celle-ci ajoute un retour à la ligne à la fin du texte. La bonne commande aurait été avec l’argument -n.

La deuxième erreur a été d’utiliser md5sum qui traite les résultats sous forme de chaîne de caractères. Si cette commande est capable de lire du contenu binaire (argument -b), il n’existe pas d’argument pour modifier le format de sortie. J’ai donc décidé de basculer vers openssl qui offre cette possibilité.

Le résultat de ces nouvelles tentatives est le suivant :

 ~$ echo -n jonas | openssl md5 -binary | base64
 ~$ nF3dVBB3NPfRgzWlJFwoaw==

Le compte est bon ! Il suffit d’ajouter le préfixe "{MD5}".

Chiffrement SHA avec OpenSSL

Pour avoir un traitement homogène entre SHA et MD5, il est aussi possible d’utiliser la commande sha1 d’OpenSSL, avec les mêmes arguments :

 ~$ echo -n jonas | openssl sha1 -binary | base64
 ~$ NaLG+uYfgHeqth+qQBlyKr8FCTw=

Là aussi le résultat est bon, au préfixe {SHA} prêt.

Script de chiffrement

Il devient alors facile de créer un script, basé sur OpenSSL.

 #!/bin/bash
 case "$1" in
   md5)
     prefix="{MD5}"
     algo="md5"
     ;;
   sha)
     prefix="SHA:"
     algo="sha1"
     ;;
   *)
     echo $1 : "Algo non géré"
     exit 1
     ;;
 esac

 echo -n $2 | openssl $algo -binary | base64

Chiffrement avec Java

Le même script aurait aussi facilement pu être écrit sous forme d’une classe Java.

En effet, le chiffrement SHA1, avec encodage base64 se traite par la ligne de code suivante :

 "SHA:" + new sun.misc.BASE64Encoder().encode(java.security.MessageDigest.getInstance("SHA1").digest(password.getBytes()))

Et l’équivalent pour MD5 est :

 "{MD5}" + new sun.misc.BASE64Encoder().encode(java.security.MessageDigest.getInstance("MD5").digest(password.getBytes()));

En assemblant tout cela, on obtient la classe suivante :

 package fr.sewatech.utils;

 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;

 import sun.misc.BASE64Encoder;

 public class JonasSecurity {
   public static void main(String[] args) {
     if (args.length < 2) {
       help();
     }

     String algo = args[0].toLowerCase();
     String prefix = null;
     String password = args[1];
     if ("md5".equals(algo)) {
       prefix = "{MD5}";
     } else if ("sha".equals(algo)) {
       prefix = "SHA:";
       algo = "sha1";
     } else {
       help();
     }

     try {
       System.out.println(prefix
           + new BASE64Encoder().encode(MessageDigest
               .getInstance(algo).digest(password.getBytes())));
     } catch (NoSuchAlgorithmException e) {
       help();
     }
   }

   private static void help() {
     System.out
         .println("Il faut 2 argument : le premier est l'algorithme (md5 ou sha), et le deuxième est le mot de passe à chiffrer.");
     System.exit(1);
   }
 }

Conclusion

Le chiffrement et l’encodage des mots de passe pour Jonas présente quelques pièges qui peuvent prendre un peu de temps. Le point principal, si on veut travailler avec les utilitaires de Linux, est de passer en mode binaire.

La façon de stocker les données d’authentification et de chiffrer les mots de passe est identique entre Jonas 4 et Jonas 5, et les techniques présentées ont été testées avec Jonas 4.8, Jonas 4.10 et Jonas 5.1 RC2.