Jabber

descr. rapide à faire. http://www.process-one.net/fr/projects/ejabberd/docs/features.html

Installation et configuration de base du serveur ejabberd

Comme d'habitude :

aptitude install ejabberd

Les questions posées sont très simples : nom du serveur (forge.evolix.net), compte administrateur jabber, mot de passe.

Dans le doute, on redémarre le service :

/etc/init.d/ejabberd restart

C'est fini pour l'installation de base.

Administration ejabberd

Créer un compte Jabber

ejabberdctl register login server password

Lister les comptes existants

ejabberctl vhost server.company.com registered-users

Pour lister les comptes de GForge et éventuellement comparer, voir l'astuce ici.

Configuration avancée

Utiliser un script d'authentification externe

Quelques scripts tout faits ici : http://www.ejabberd.im/extauth

Tout accepter

Pour utiliser le script d'exemple fourni (/usr/share/doc/ejabberd/examples/extauth/check_pass_null.pl), il faut penser à installer le module Unix::Syslog.pm

aptitude install libunix-syslog-perl

Il faut en plus modifier le fichier de configuration de ejabberd

vim /etc/ejabberd/ejabberd.cfg

Commentez

%%{auth_method, internal}.

Décommentez

{auth_method, external}.
{extauth_program, "/usr/share/doc/ejabberd/examples/extauth/check_pass_null.pl"}.

Evidemment, pour utiliser votre propre script, remplacez /usr/share/doc/ejabberd/examples/extauth/check_pass_null.pl par le bon chemin.

Relancez ejabberd

/etc/init.d/ejabberd restart

Authentification GForge

On part du script Perl check_postgresql.pl que l'on trouve ici : http://www.ejabberd.im/files/efiles/check_postgresql.pl.txt

Pour le mettre en place, appliquez la même démarche que pour le script d'exemple.

On veut que ce script (executé en tant qu'ejabberd) se connecte (en tant que gforge) à la base gforge. Il va falloir modifier un peu pg_hba.conf et pg_ident.conf pour celà (d'autres méthodes existent peut-etre).

Dans pg_hba.conf, ajoutez la ligne (avant la ligne qui concerne toutes les bases (all all ident sameuser)):

local    gforge      gforge                            ident jabber

et ajoutez la ligne correspondant à cette identité 'jabber' dans le fichier pg_ident.conf

jabber  ejabberd        gforge

Comme celà 'casse' la connexion pour gforge, j'ajoute aussi :

jabber  gforge          gforge

Il y a surement moyen de faire ça sans casser la connexion gforge mais n'étant pas expert en postgresql, je n'ai pas approfondi.

On peut vérifier, après avoir redémarrer postgres, que ejabberd se connecte bien :

su ejabberd
psql -U gforge gforge

Maintenant, modifions le script Perl.

Réglez bien ces variables :

my $dbUser="gforge";  # The username to connect to postgresql
my $dbName="gforge";	# The name of the database inside postgresql
my $dbTable="users"; # The name of the table inside the database
my $fieldUser="user_name";   # The name of the field that holds jabber user names
my $fieldPass="user_pw";   # The name of the field that holds jabber passwords

GForge stocke les mots de passe en md5, et ejabberd nous les donne en clair, on va les chiffrer avant de faire la requête SQL

Au début du script :

use Digest::MD5 "md5_hex";

et après le nettoyage du password (est-il encore nécessaire ?)

$password = md5_hex($password);

Modifions maintenant la requête SQL pour la valeur 'auth' dans le SWITCH:

#c'est subtil, il faut remplacer $jid par $user
$orden = "psql -U $dbUser $dbName --command \"select count(*) from $dbTable where $fieldUser='$user' and $fieldPass='$password';\" | 
		grep '^ *[1-9][0-9]* *\$' &> /dev/null";

Et voilà le tour est joué.

Occupons nous maintenant de la valeur 'isuser' dans le SWITCH:

Changer $jid par $user et voilà. On peut décommenter l'instruction syslog, c'est toujours utile pour débugguer ses requêtes SQL...

Enfin, vous pouvez élaborer des requêtes plus fines, vérifiant par exemple si le compte GForge a été confirmé par e-mail (status = 'A').

Enfin, la valeur 'setpass' dans le SWITCH:

Pour le changement de mot de passe, c'est un peu plus compliqué, étant donné que GForge stocke deux fois le mot de passe, sous deux formes différentes (une fois en md5 hexadécimal, et une fois selon la méthode définie dans $unix_cipher dans le fichier /etc/gforge/local.inc

Pour l'instant, je ne traite que mon cas, à savoir MD5. Ce n'est pas le même MD5 qu'avant, il n'est pas hexadécimal cette fois ci. GForge utilise la fonction crypt() du php qui devine l'algorithme à utiliser d'après le salt donné. La fonction crypt() de Perl ne le fait pas, elle fait toujours du DES. Par ailleurs, nous ne pouvons pas utiliser les algorithmes MD5 du module Digest::MD5 employé précédemment car ils n'intègrent pas la notion de salt.

Nous allons plutôt utiliser le module Crypt::PasswdMD5.

aptitude install libcrypt-passwdmd5-perl

Dans notre script, on va écrire une fonction qui génère le salt :

sub gensalt
{
    my @salt = ( '.', '/', 0 .. 9, 'A' .. 'Z', 'a' .. 'z' );
    my $salt;
    $salt .= (@salt)[rand @salt];
    $salt .= (@salt)[rand @salt];
    return $salt;
}

Cette fonction nous retournera un salt de longueur 2, tout comme le salt employé par GForge.

Ensuite, pour chiffrer le mot de passe en MD5 avec salt :

use Crypt::PasswdMD5 "unix_md5_crypt";
$unix_password = unix_md5_crypt( $password, gensalt() );

Maintenant que tout est généré, il n'y plus qu'à mettre à jour la table SQL. Ajoutez ceci en haut du script, avec les autres variables : my $fieldUnixPass="unix_pw";

Et dans le cas setpass du SWITCH :

$unix_password =~ s/\$/\\\$/g;
$orden = "psql -U $dbUser $dbName --command \"UPDATE $dbTable SET $fieldPass='$password', $fieldUnixPass='$unix_password' where $fieldUser='$user';\" | grep '^.*[1-9][0-9]* *\$' &> /dev/null";
syslog(LOG_INFO,"Executing: %s",$orden);

# if command returned 0 we return 1
$result = !system($orden);

ATTENTION : le grep a légèrement changé par rapport à précédemment et on a aussi échappé les $ du $unix_password car sinon ils seront interprétés par le shell !

Groupes de contacts partagés ( Shared Rosters )

Avant toute chose, pensez à activer le module shared_roster dans le fichier de configuration d'ejabberdctl.

Ici, pour synchroniser les groupes de contacts Jabber avec les groupes de projet GForge, on va écrire un petit script. Il utilisera ejabberctl pour créer les groupes et ajouter des utilisateurs. Sous Debian, la version actuelle du paquet (juillet 08) ne permet pas de lister les rosters déjà existants ce qui impose de recréer à chaque fois tous les groupes. Une autre solution serait de stocker cette liste à la création dans une base de données annexe. Nous avons préféré modifier le paquet Debian.

Modifier le package Debian d'ejabberd

Script sans modifier le paquet

Si toutefois vous ne souhaitez pas utiliser cette version modifiée, voici un script qui recrée tout à chaque fois.

#!/usr/bin/perl -w

#synchro v1
#recrée tous les groupes et remet dedans tous les users. (pas top)

#Get groups name, unix_name and group_id
#name will be the roster name, unix_name will be the roster id


$cmd_get_groups='psql -tAU gforge gforge -c "select unix_group_name,group_name from groups where group_id>5;"';
open(GROUPS, "$cmd_get_groups |");

my @unix_group_name = ();

#création des groupes
while(<GROUPS>)
{
    chomp;
    @group = split (/\|/);
    $cmd_create_roster="ejabberdctl srg-create $group[0] forge.evolix.net 'Projet $group[1]' 'Le groupe du projet $group[1]' $group[0]";
    system $cmd_create_roster;
    push(@unix_group_name,$group[0]);
}
close GROUPS;

#récupération des users
foreach $group (@unix_group_name)
{
    $cmd_get_users = "psql -tAU gforge gforge -c \"select users.user_name from users,user_group,groups where users.user_id=user_group.user_id and groups.unix_group_name='$group' and groups.group_id=user_group.group_id;\"";
    open(USERS,"$cmd_get_users |");
    
    #ajout de tous les users du groupe courant.
    while(<USERS>)
    {
        chomp;
        $cmd_add_user="ejabberdctl srg-user-add $_ forge.evolix.net $group forge.evolix.net";
        system $cmd_add_user;
    }
    close USERS;
}

A chaque fois, ce script recrée tout depuis zéro, ce qui prend beaucoup de temps. On préfera donc le script avec la version modifiée du paquet.

Script Perl avec le nouveau paquet

Voici un script beaucoup plus malin, qui ne crée que le strict nécessaire et qui nettoie les groupes de leurs utilisateurs supprimés.

#!/usr/bin/perl -w

#synchro v2
#ne crée que ce qu'il faut
#n'efface pas les groupes en trop dans jabber (on peut vouloir des groupes indépendants de GForge)

#Récupère les groupes jabber
$cmd_get_jabber_groups='ejabberdctl srg-list-groups forge.evolix.net';
open(JABBER_GROUPS, "$cmd_get_jabber_groups |");
#on crée un hash des groups
my %jabber_groups=();
while(<JABBER_GROUPS>)
{
    chomp;
    $jabber_groups{$_}++;
}
close(JABBER_GROUPS);

#Récupère les groupes gforge (unix_name,name)
$cmd_get_gforge_groups='psql -tAU gforge gforge -c "select unix_group_name,group_name from groups where group_id>5;"';
open(GFORGE_GROUPS, "$cmd_get_gforge_groups |"); # donne les groupes et les noms de groupe

#création des groupes avec comparaison au hash %jabber_groups
my @gforge_groups=();
while(<GFORGE_GROUPS>)
{
    chomp;
    ($unix_name,$name) = split (/\|/);
    unless($jabber_groups{$unix_name})
    {
        $cmd_create_roster="ejabberdctl srg-create $unix_name forge.evolix.net 'Projet $name' 'Le groupe du projet $name' $unix_name";
        system $cmd_create_roster;
        print "Group $unix_name created.\n";
        #on pourrait ici ajouter des contacts commums à tous comme support@forge.evolix.net
        #il est peut etre plus simple de faire un groupe @all@ qui voit le groupe contenant le support.
    }   
    push(@gforge_groups,$unix_name);
}
close GFORGE_GROUPS;


#pour chaque groupe GForge, on check la liste d'users

foreach $group (@gforge_groups)
{
    #Récupère les users jabber
    $cmd_get_jabber_users="ejabberdctl srg-get-info $group forge.evolix.net";
    open(JABBER_USERS, "$cmd_get_jabber_users |");
    #on crée un array des users
    my @jabber_users=();
    while(<JABBER_USERS>)
    {
        if( /^members: / )
        {
            s/^members: //;
            s/\@forge\.evolix\.net//g;
            @jabber_users=split;
            last;
        }
    }
    close(JABBER_USERS);
    my %jabber_users_hash=();
    foreach (@jabber_users)
    {
        $jabber_users_hash{$_}++;
    }
    #on a un hash des users déjà dans le groupe jabber
    
    #on va comparer à ceux de GForge
    $cmd_get_gforge_users = "psql -tAU gforge gforge -c \"select users.user_name from users,user_group,groups where users.user_id=user_group.user_id and groups.unix_group_name='$group' and groups.group_id=user_group.group_id and users.status='A';\"";
    open(USERS,"$cmd_get_gforge_users |");
    
    #ajout des users du groupe courant non présents dans jabber.
    while(<USERS>)
    {
        chomp;
        
        unless($jabber_users_hash{$_}++)
        {
            $jabber_users_hash{$_}++;
            $cmd_add_jabber_user="ejabberdctl srg-user-add $_ forge.evolix.net $group forge.evolix.net";
            system $cmd_add_jabber_user;
            print $_," added in $group.\n";
        }
        
    }
    close USERS;
    
    #effaçage des users effacés dans gforge
    foreach (keys(%jabber_users_hash))
    {
        if($jabber_users_hash{$_} == 1) # =2 signifie dans les 2, =1, uniquement dans jabber
        {
            $cmd_del_jabber_user="ejabberdctl srg-user-del $_ forge.evolix.net $group forge.evolix.net";
            system $cmd_del_jabber_user;
            print $_," deleted from $group.\n";
        }
    }
}

Idées en vrac

faire une interface au plugin activable par interface gforge chaque groupe peut choisir d'avoir un roster chaque user peut choisir d'apparaitre ou non dans les rosters