Transférer des mots de passe d’une base de données MySQL/PHP vers un annuaire LDAP

J’ai récemment voulu récupérer des mots de passe depuis une base de donnée MySQL (alimentée par PHP) pour les mettre dans un annuaire LDAP, et comme je n’ai pas trouvé immédiatement la solution à ce problème, je consigne ici la procédure que j’ai suivie, pour qu’elle puisse être utile à un autre (cet autre pouvant être celui que je serai dans un an ou deux).

Les données du problème

  • J’ai une base de données MySQL, associée à une application en PHP, Ilias Open Source, qui contient des mots de passe. Naturellement, ces mots de passe ne sont pas stockés en clair dans la base de données, ils sont hachés en utilisant MD5.
  • J’ai un annuaire openLDAP qui contient des données utilisateurs et notamment des mots de passe. LDAP n’est pas très exigent en ce qui concerne les mots de passe : il lui suffit que la chaîne correspondant au mot de passe commence par le nom de l’algorithme de hachage utilisé pour produire la chaîne qui suit. Bien sûr, il faut que l’algorithme choisi soit connu d’openLDAP (il est possible d’ajouter des modules à la compilation pour le faire fonctionner avec tous les algorithmes couramment utilisés pour hacher les mots de passe).
  • Je veux que les mots de passe des utilisateurs présents dans l’annuaire soient ceux qu’ils ont dans la base de données relationnelle.

Le problème

A première vue, il n’y a pas de problème : je prends le mot de passe haché dans ma base de données et je le mets dans l’annuaire en le faisant précéder de {MD5}. C’est d’ailleurs ce que j’ai essayé de faire tout d’abord et cela ne fonctionne pas.

En cherchant un peu, on trouve rapidement l’explication de cela et elle est assez simple : l’algorithme MD5 produit une empreinte sous la forme d’une séquence de 128 bits, soit 16 octets. Naturellement, une telle suite de 16 octets ne peut pas être représentée en texte “normal” (ascii), il faut donc lui faire subir un traitement pour pouvoir l’imprimer ou même simplement l’afficher sur un écran.

C’est là que le problème se pose : la fonction MD5 de php crée, par défaut, une représentation de cette séquence sous la forme d’une suite de 32 chiffres hexadécimaux (en Python un tel résultat est obtenu avec la fonction hexdigest() du module md5 (ce module est déconseillé dans les versions de Python supérieures à la 2.5, mais le programme que j’ai écrit était en Python 2.3) ), openLDAP (je suppose que c’est le fonctionnement standard de toutes les implémentations du protocole LDAP), en revanche, prend directement la séquence d’octets (équivalent de la fonction Python digest() du module md5) et l’encode en base64, un algorithme destiné à représenter des données binaires en texte, utilisé, par exemple, pour encoder les pièces jointes des messages électroniques.

La solution

Après beaucoup de tâtonnements et (trop) de recherches, j’ai réussi à trouver la formule qui me donne satisfaction. La voici (en Python) :

En supposant que pw_php est le mot de passe que j’ai obtenu de la base MySQL et pw_ldap le mot de passe que je vais inscrire dans l’annuaire LDAP.

pw_ldap = "{MD5}" + base64.encodestring(pw_php.decode("hex"))

La méthode decode() de l’objet chaîne, avec le paramètre “hex” décode l’empreinte encodée en caractères hexadécimaux, pour obtenir à nouveau la séquence de 16 octets. Cette séquence est alors encodée en base64 grâce à la fonction encodestring() du module base64. Comme je l’ai indiqué plus haut, le début de la chaîne de caractères du mot de passe indique l’algorithme utilisé pour hacher le mot de passe (ici MD5), entre accolades.

Blogged with Flock

Tags: , , ,

Linkroll

Steve Rubel propose 10 blogging hacks après avoir proposé d’autres astuces sur RSS et Technorati. Il y a des choses intéressantes dans ce billet qui m’ont donné quelques idées.

Surtout, en accord avec une réflexion que je me fais depuis quelque temps déjà et que me confirme le blog Arkandis (en citant un article de Cory Doctorow publié sur O’Reilly Network en 2002 qui est précisément le texte qui m’a donné envie d’avoir un blog, il y a quelque temps déjà), j’ai décidé d’utiliser ce blog pour poster des liens.

En effet, je me rends compte que j’oublie facilement les liens que j’enregistre dans del.icio.us et que je ne les retrouve plus quand j’en ai besoin. Je me dis (peut-être à tort) que si je me force à mettre quelques notes sur chaque lien de façon à ce que ces notes apparaissent ici, je les mémoriserai mieux.

Pour l’instant, j’ai un tag particulier, linkroll pour identifier les signets qui seront affichés ici chaque jour. Peut-être que je déciderai de ne plus recourir à ce tag et de tout poster ici, on verra ; peut-être aussi que je déciderai de ne pas poster quotidiennement et de le faire une fois par semaine par exemple. Je suis à cet égard ouvert à toutes vos propositions et tous vos commentaires : quel est selon vous le meilleur format et la meilleure fréquence ?

Je n’ai pas réussi à faire fonctionner le script que j’ai trouvé sur schulzone.org (j’ai laissé tomber à la première erreur de cpan, un jour il faudra peut-être que j’apprenne à utiliser cet outil…). J’ai donc décidé de faire un script équivalent en python, en utilisant Delicious Python et wordpresslib.py. (En fait, j’ai vu plus tard, trop tard, que la fonction daily blog de del.icio.us doit pouvoir fonctionner avec wordpress, mais je n’ai pas essayé.)

Le script est ici. Voici comment l’utiliser :

1. Télécharger la bibliothèque wordpresslib.py :

$ mkdir wpl

$ cd wpl

$ wget \
http://www.blackbirdblog.it/download/software/wordpresslib.zip

2. La décompresser et l’installer :

$ unzip wordpresslib.zip

$ sudo python setup.py install

3. Télécharger Delicious Python :

$ wget http://delicious-py.berlios.de/delicious-0.2.5.py

J’ai choisi de ne pas installer ce script (j’avoue que c’est parce que je n’ai pas eu le courage d’aller chercher à la main dans quel répertoire les modules python doivent être installés). Il faut donc qu’il soit dans le même répertoire que le script linkroll.py. J’ai créé un lien symbolique delicious.py :

$ ln -s delicious-0.2.5.py delicious.py

4. Il ne reste plus qu’à lancer le script :

python linkroll.py

Bien sûr, il est préférable de créer une tâche planifiée avec crontab pour le lancer régulièrement.

Conversion de fichiers OpenOffice.org en images

Laurent Verdier a demandé sur la liste de diffusion des personnes ressources TICE de l’académie de Bordeaux (http://listes.ac-bordeaux.fr/wws/info/pressour) comment créer une image à partir d’un document de traitement de texte. Il a l’habitude de passer par Open Office, puis Gimp pour faire ces manipulations à la main : enregistrement en postscript avec la fonction ‘imprimer dans un fichier’, puis ouverture dans The Gimp et enregistrement au format d’image souhaité. Cependant, il souhaiterait éviter cette procédure répétitive.

Je proposerai la démarche suivante (qui ne marche que sous Linux, en tout cas dans son intégralité) :

Dans un premier temps, je vais créer une imprimante de conversion en PDF en utilisant l’utilitaire spadmin d’OOo. Sur ma Fedora Core 3, cet outil n’est pas dans le $PATH par défaut, j’ai donc dû le chercher avec la commande :

$ locate spadmin

qui m’a permis de le trouver sous le nom /usr/lib/ooo-1.1/program/spadmin.bin. Il est important que toutes les instances d’Open Office soient fermées pour que la suite fonctionne normalement.

Je clique sur le bouton ‘Nouvelle imprimante’, puis je choisis ‘Connecter un convertisseur PDF’, puis ‘Pilote par défaut’. J’accepte la ligne de commande qui m’est proposée par défaut et je choisis un nom de répertoire pour stocker mes fichiers PDF, par exemple mes_pdf dans mon répertoire personnel.

Je choisis alors “conversion_pdf” comme nom pour l’imprimante (je pourrais mettre des espaces, mais je préfère toujours l’éviter) et je clique sur ‘Créer’.

spadmin

J’ai désormais tout ce qu’il faut pour pouvoir convertir n’importe quel document OOo (ou tout document compatible) en PDF, en ligne de commande, avec la commande :

$ ooffice -invisible -pt conversion_pdf fichier_a_convertir.sxw

qui me crée un document appelé fichier_a_convertir.sxw.pdf dans le répertoire que j’ai choisi.

Il ne me reste plus qu’à convertir ces PDF en images. Ce qui se fait assez facilement avec l’utilitaire convert de la suite Imagemagick, qui est installée par défaut sur la plupart des distributions récentes.

$ convert fichier.pdf fichier.png

Me fait un fichier PNG à partir de mon fichier PDF. Ce qui est bien ce que l’on recherchait !

Mais le lecteur tâtillon va me dire que cette méthode ne prend pas en compte les fichiers PDF comportant plusieurs pages et que si je donne un tel fichier à ma commande, l’image produite sera celle de la dernière page de mon document…

Qu’à cela ne tienne :

$ convert fichier.pdf png:fichier.png

Va me générer autant de fichiers PNG qu’il y a de pages dans mon document de départ, en leur donnant un numéro : fichier-1.png, fichier-2.png etc.

C’est déjà bien, mais comme je suis paresseux, je veux automatiser tout cela. Il me suffit donc d’écrire un script shell qui va d’abord créer les fichiers PDF, puis les transformer en images :


#! /bin/bash
# Types de fichiers à convertir
TYPES='*.doc *.rtf *.sxw'
# Répertoire à surveiller
REP_A_SURV=~/a_convertir
# Répertoire contenant les fichiers PDF générés (tel que défini avec spadmin)
REP_PDF=~/mes_pdf
# Répertoire contenant les images
REP_IMG=~/mes_pdf/img


# Je me place dans le répertoire à surveiller, puis je convertis tous les documents dont l'extension est dans $TYPES en PDF
cd $REP_A_SURV
ooffice -invisible -pt conversion_pdf $TYPES


# Je convertis ensuite les documents du répertoire contenant les PDF
cd $REP_PDF
ls *.pdf \
|sed 's/\(\(.*\).pdf\)$/convert "\1" png:"\2.png"/' \
|sh
# Eventuellement, je supprime les fichiers PDF
# rm *.pdf
mv *.png $REP_IMG

La ligne qui commence par ls *.pdf est un peu plus compliquée : je fais la liste des fichiers portant l’extension .pdf, et pour chacun des fichiers de cette liste, j’applique une fonction de l’éditeur sed qui crée une commande en concaténant la chaîne “convert”, le nom du fichier pdf (\1, qui correspond à la première paire de parenthèses, soit l’ensemble du nom du fichier)) et le nom du fichier PNG à créer : le nom du fichier PDF sans l’extension .pdf et avec l’extension .png (le nom du fichier sans extension est obtenu avec \2, qui correspond à la deuxième paire de parenthèses dans l’expression régulière.

Voilà ! Mes fichiers images sont dans le répertoire que j’ai choisi. Je peux même ajouter une tâche à ma crontab, de façon à ce que cette conversion soit faite toutes les nuits, pour que je n’aie qu’à enregistrer un document dans le répertoire à surveiller pour retrouver les images correspondantes à l’emplacement approprié.

Si je le souhaite, je peux également utiliser les innombrables options de convert pour choisir la taille des images, par exemple, ou pour leur faire subir n’importe quel traitement.

Télécharger le script

Utiliser VUE sous Linux

VUE est une application open source de concept mapping créé à l’université de Tufts. Sa principale originalité repose dans le fait qu’elle peut être connectée à un dépôt de données, qui peuvent facilement être utilisées dans les cartes réalisées. Plus simplement, ce que j’aime avec ce programme, c’est qu’il me permet de faire des concept maps et des diagrammes simplement.
VUE

Pendant longtemps, seule une version Windows avec une machine java embarquée était disponible en téléchargement. Pourtant, j’avais connu ce programme lors d’un colloque sur le elearning organisé en Italie et je l’avais vu tourner sur un Mac…

Bien sûr, comme il s’agit d’un programme open source et que c’est du Java, il était possible de l’utiliser sous Linux avec un minimum de bricolage. Depuis peu, une version Mac est disponible et il est très facile de la faire fonctionner sur un Linux. Voici la démarche que j’ai suivie :

– Télécharger le zip de la version Mac ; pour ce faire, il faut être inscrit.

– Dézipper le paquet (je l’ai mis dans /usr/local/vue)

– Il suffit alors de lancer le fichier jar /usr/local/vue/VUE.app/Contents/VUE.jar avec la commande :

java -jar /usr/local/vue/VUE.app/Contents/VUE.jar

Ca y est, normalement vue fonctionne !

Il reste cependant quelques petites choses à améliorer.

Par exemple, il faut pouvoir utiliser une commande plus pratique pour le lancer. Je crée donc un script bash, que je place dans /usr/local/bin (ce répertoire est dans mon chemin d’exécution ($PATH) par défaut) et que j’appelle vue, simplement.

Ce fichier contient seulement les deux lignes suivantes :

#! /bin/bash
java -jar /usr/local/vue/VUE.app/Contents/VUE.jar

Dès lors, je peux lancer le programme en saisissant simplement vue dans un terminal.

Par ailleurs, je remarque très vite que l’ouverture des url ne fonctionne pas. Un petit coup d’oeil sur les messages d’erreur (assez verbeux, heureusement) affichés sur le terminal m’indique que celui-ci essaie d’invoquer la commande netscape pour ouvrir ces liens… Je fais un premier test en créant un lien symbolique vers /usr/bin/firefox, que j’appelle /usr/local/bin/netscape. Ca fonctionne, mais je rencontre tout de même un petit problème : Firefox refuse de se lancer si une autre instance est en cours d’exécution avec le même profil ; et il est rarissime que je n’ai pas déjà un Firefox ouvert.

J’en suis donc quitte pour lire un (tout) petit peu de doc sur Firefox, pour trouver l’option -remote qui permet de passer une commande à une instance de Firefox en cours d’exécution. Je supprime donc mon lien /usr/local/bin/netscape et je le remplace par un script ainsi formulé :

#! /bin/bash
/usr/bin/firefox -remote "openurl($*), new-tab"

Ce qui a pour effet d’ouvrir l’url passée en paramètre ($*) dans un nouvel onglet du Firefox courant en invocant la commande openurl().

Après cela, j’ai l’impression que tout fonctionne normalement, mais n’hésitez pas à me signaler si vous remarquez une fonctionnalité inactive.

Outils de productivité…

Je viens de découvrir (non sans un certain effroi) que ce à quoi j’ai passé la soirée d’hier existait déjà. Il s’agit d’un fichier PDF qui contient l’intégralité des gabarits du D*I*Y Planner. Je dois avouer que pour l’instant et malgré mes espoirs, ce système n’a pas vraiment amélioré ma productivité… ;-)

Alors pour ne pas avoir travaillé pour rien, j’ai cherché à justifier mes efforts et je suis arrivé à trouver un moyen pour concaténer des fichiers postscript (ainsi que les options). Voici la commande :

$ gs -dNOPAUSE -dBATCH -sDEVICE=pswrite \
-sOutputFile=myDiyplanner2.ps diyplanner2_a5-even*

Je peux ainsi créer plusieurs sous-parties des fichiers PDF d’origine puis les concaténer pour avoir une configuration utilisable directement (par exemple avec 52 fois la page ‘weekly planning’ et avec les pages que je souhaite et sans celles qui ne m’intéressent pas). Je pense aussi faire des petits paquets qui pourront être utilisés comme compléments : si un jour j’ai besoin de 10 exemplaires des 3 ou 4 pages qui concernent la description d’un projet, je pourrai simplement imprimer dix fois le fichier projet.pdf. Si je le fais vraiment, je ne manquerai pas de vous en informer.