This is a small script to authenticate Jabber users with an external MySQL database. You can free define table and columns for username and password in the settings part of the script. The password should be stored with the ENCRYPT() function in the database.
First edit the Jabber configuration file (\etc\ejabberd\ejabberd.conf) and change the authentication method:
{auth_method, external}.
{extauth_program, "/etc/ejabberd/auth_mysql.pl"}
Now create the perl script /etc/ejabberd/auth_mysql.pl with the following content and changed settings:
#!/usr/bin/perl
# Mysql external auth script
# Features: auth isUser and change password
# Password is an encrypted password !!
# 2009-02-04 - by Mogilowski Sebastian - http://www.mogilowski.net
# Settings
my $sDatabaseHost='SERVER'; # The hostname of the database server
my $sDatabaseUser="USER"; # The username to connect to mysql
my $sDatabasePass='PASS'; # The password to connect to mysql
my $sDatabaseName="DATABASE"; # The name of the database contain the user table
my $sUserTable="TABLE"; # The name of the table containing the username and password
my $sUsernameTableField="USERFIELD"; # The name of the field that holds jabber user names
my $sPasswordTableField="PASSWORDFIELD"; # The name of the field that holds jabber passwords
# Libs
use DBI;
use DBD::mysql;
while(1) {
my $sBuffer = "";
my $readBuffer = sysread STDIN,$sBuffer,2;
my $iBufferLength = unpack "n",$sBuffer;
my $readBuffer = sysread STDIN,$sBuffer,$iBufferLength;
my ($sOperation,$sUsername,$sDomain,$sPassword) = split /:/,$sBuffer;
my $bResult;
SWITCH: {
$sOperation eq 'auth' and do {
$bResult = 0;
$connect = DBI->connect('DBI:mysql:'.$sDatabaseName, $sDatabaseUser, $sDatabasePass) || die "Could not connect to database: $DBI::errstr";
$query = "SELECT $sPasswordTableField FROM $sUserTable WHERE $sUsernameTableField='$sUsername';";
$statement = $connect->prepare($query);
$statement->execute();
while ($row = $statement->fetchrow_hashref()) {
$sCryptstring = crypt($sPassword,$row->{$sPasswordTableField});
if ($row->{$sPasswordTableField} eq $sCryptstring) {
$bResult = 1;
}
}
},last SWITCH;
$sOperation eq 'setpass' and do {
$connect = DBI->connect('DBI:mysql:'.$sDatabaseName, $sDatabaseUser, $sDatabasePass) || die "Could not connect to database: $DBI::errstr";
$myquery = "UPDATE $sUserTable SET $sPasswordTableField=ENCRYPT('$sPassword') WHERE $sUsernameTableField='$sUsername';";
$statement = $connect->prepare($myquery);
$statement->execute();
$bResult = 1;
},last SWITCH;
$sOperation eq 'isuser' and do {
$bResult = 0;
$connect = DBI->connect('DBI:mysql:'.$sDatabaseName, $sDatabaseUser, $sDatabasePass) || die "Could not connect to database: $DBI::errstr";
$myquery = "SELECT count(*) AS iCount FROM $sUserTable WHERE $sUsernameTableField='$sUsername';";
$statement = $connect->prepare($myquery);
$statement->execute();
$row = $statement->fetchrow_hashref();
if($row->{'iCount'} >= 1){
$bResult = 1;
}
},last SWITCH;
};
my $sOutput = pack "nn",2,$bResult ? 1 : 0;
syswrite STDOUT,$sOutput;
}
closelog;
Or you download the script here: auth_mysql.pl (1 KB)
Now make the script executeable:
chmod +x /etc/ejabberd/auth_mysql.pl

Als gute alternative hat sich auch
https://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver
herausgestellt. Man kann damit sogar die Server basierten Kontaktlisten, und offline Messages in der Datenbank speichern.
Hi,
ja dies kannst man aber immer noch zusätzlich machen.
Der Sinn war hier alle Benutzer auch für andere Dienste in einer Datenbank zu haben.
So werden alle Benutzer in einer zentralen Datenbank gespeichert.
Es ist also als Ergänzung zur internen Jabber Datenbank gedacht die wiederrum auch in einer eigenen MySQL Datenbank gespeichert werden kann.
Nachtrag:
https://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver
In dieser Variante liegt das Passwort unverschlüsselt also im Klartext in der Datenbank. In meiner Variante wird das Passwort als Hash gespeichert.
Hi Sebastian,
danke für dein Script, ich hab lange nach einem guten Script gesucht, deins hat dan nam Ende gewonnen. Wenn dann auf meinem neuen Jabber Server soweit alles läuft werd ich auf meinem Blog einen Post schreiben, dann wird dein Blog und das Script noch mal ausführlich gelobt!
Hi du,
bin grad dabei dein Scrip einzubinden, aber leider bricht der ejabber Server immer wieder den Start ab mit folgender Meldung:
** Reason for termination =
** {badarg,[{extauth,call_port,2},
{ejabberd_auth,'-check_password_with_authmodule/3-fun-0-',4},
{lists,dropwhile,2},
{ejabberd_auth,check_password_with_authmodule,3},
{cyrsasl_plain,mech_step,2},
{cyrsasl,server_step,2},
{ejabberd_c2s,wait_for_feature_request,2},
{p1_fsm,handle_msg,10}]}
Wenn ich den auth auf die interne DB setze funktioniert alles bestens.
Mit einen PHP Script kome ich ohne Probleme auf die Datenbank, die Daten für die DB habe ich in deinem Script schon zich mal überprüft. Die Felder in der tabelle heisen bei mir Benutzer und Passwort, hab auch auf Case sensitive geachtet. ich weiß Ferndiagnosen sind schwer aber evtl sagt dir die Fehlermeldung die ich gepostet hab etwas.
Gruß
Philipp
Hallo Sebastian,
den Kommentar vorher kannst du löschen.
Den ejabberd Server habe ich nun soweit das er mit deinem Script arbeitet, nur habe ich Probleme mit dem Authentifizieren. Leider kommt bei mir immer die Meldung “Authentication error: Not authorized”.
In meiner SQL Tabelle habe ich zwei Felder “Benutzer” und “Passwort” im Benutzerfeld steht “foo@bar.de” im Passwortfeld ist das Passwort in md5 abgelegt. In deinem Script habe ich alle Variablen angepasst. Als System habe ich Debian Lenny 64Bit, Authentifizieren über die Interne DB geht, aber das möcht ich ja nicht. Kannst du mir eine Beispiel SQl Tabelle zukommen lassen. Muss ich in der jabber.cfg irgendwie die Authentifizierungsmetoden abändern? Kann ich dein Script testen ob es die Daten bei mir in der SQL Tabelle findet?
Gruß
Philipp
Hallo,
ich verwende “crypt” bzw. “ENCRYPT” in meinem Skript. Du musst wenn du MD5 verwenden willst diese Funktionen ersetzen. Crypt war hier damals notwendig, da dies von einer anderen Software so verwendet wurde und diese nicht modifiziert werden sollte.
cheers
Sebastian
Hi Sebastian,
auf den Trichter bin ich gestern Abend auch gekommen das ich wohl falsch liege mit MD5, dennoch danke für deine Antwort!
Ich weis nicht so recht mit was ich crypt() ersetzen soll. Ich habe mehrere Anhaltspunkte gefunden Digest::md5, crypt(pass, $1$salt), nur kommt bei den beiden möglichkeiten nicht der Hash raus wie bei md5. Leider kann ich nicht so gut Programmieren das diese Aufgabe nun einfach für mich wäre, hättest du einen Tipp für mich?
Hi,
das kommt drauf an was du hier genau verwendest.
http://perldoc.perl.org/Digest/MD5.html gibt dir vielleicht den entsprechenden Hinweis.
Wichtig sind eigentlich nur die Stellen:
“$sCryptstring = crypt($sPassword,$row->{$sPasswordTableField});” in auth
und “… $sPasswordTableField=ENCRYPT(‘$sPassword’) … ” in setpass
Gruß
Sebastian