Authenticate ejabberd with an mysql database

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 (1015 Downloads)

Now make the script executeable:

chmod +x /etc/ejabberd/auth_mysql.pl

This Post Has 26 Comments

    1. 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.

  1. 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!

  2. 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

  3. 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

    1. 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

  4. 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?

  5. 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

  6. Hallo Sebastian,

    Erst mal vielen Dank für das Skript!

    Ich wollte bewerkstelligen, dass ejabberd zu Benutzer-Authentifizierung auf die phpbb-Datenbank zugreift (phpbb-version 3.08), aber keine Änderungen vornehmen kann.
    Aus diesem Grund habe ich bei der Erstellung des MySQL-Benutzers mit GRANT nur SELECT genommen.
    gibt es noch etwas worauf ich achten sollte, wie zum Beispiel die Passwortverschlüsselung?
    Und macht es Sinn im Skript die Operationen ‘auth’ und ‘setpass’ aus zu kommentieren? -Diese sind ja für neue Authentifizierungen bzw Änderungen von Passwörtern vorgesehen, wenn ich es richtig verstehe.
    In ejabberd habe ich die Registrierung neuer User schon abgelehnt.
    Über Tipps freue ich mich, da ich nichts zuhauen will!

    Nette Grüße

    Andreas

    1. Hallo Andreas,

      also erstens musst du schauen wie das Passwort von phpbb gespeichert wird. Also crypt oder md5 usw.

      Ich glaube das ist bei phpbb MD5 aber informiere dich da zur Sicherheit nochmal.

      Die Funktionen komplett auskommentieren würde ich nicht, da Jabber diese ja aufrufen wird. Ich würde einfach in den Funktionen nichts machen bzw. am besten noch einen für Jabber verständlichen Fehler zurückgeben.

      Übrigens könntest du durchaus das Passwort der User via Jabber änderbar machen. Wenn das Passwort wieder als MD5 gespeichert wird ist dies für phpbb kein Problem.

      Also einfach alle “crypt” im Skript durch “md5” ersetzen und es sollte funktionieren. Auch das ändern der Passwörter via Jabber.

      Habe leider kein Setup mit dem ich das testen könnte würde mich aber ein Feedback freuen wenn du es entsprechend umgesetzt hast. Würde das selbe Skript mit MD5 hier auch mal veröffentlichen, da immer wieder anfragen deswegen kommen.

      cheers

      Sebastian

  7. Hallo Sebastian,

    also die machen da anscheinend ihr eigenes Ding mit der Hashgenerierung. Da steht was von salt und md5. Allerdings glaube ich den richtigen Teil zum Überprüfen der eingegebenen Passwörter gefunden zu haben:

    /**
    * Check for correct password
    *
    * @param string $password The password in plain text
    * @param string $hash The stored password hash
    *
    * @return bool Returns true if the password is correct, false if not.
    */
    function phpbb_check_hash($password, $hash)
    {
    $itoa64 = ‘./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz’;
    if (strlen($hash) == 34)
    {
    return (_hash_crypt_private($password, $hash, $itoa64) === $hash) ? true : false;
    }

    return (md5($password) === $hash) ? true : false;
    }

    und da wird anscheinen nur noch md5 geprüft, obwohl es anders generiert wird.

    Also das skript habe ich bei abschnitt auth von crypt auf md5 umgeändert.

    Allerdings funktioniert es bisher anscheinend nicht. In /var/log/ejabberd/ejabber.log habe ich keine direkte Fehlermeldung erhalten.
    Der jabber Client melde mir auf jeden Fall einen Authentifizierungsfehler.

    1. Hallo,

      vielleicht fängst du zuerst damit an dir ein kleines Perl Skript zu schreiben, dass dir nur das verschlüsselte Passwort aus dem unverschlüsselten Passwort erzeugt.

      Also zum Beispiel sowas:

      #!/usr/bin/perl
      use Digest::MD5 qw(md5 md5_hex md5_base64);
      my $encrpass = md5($password); # binary
      print $encrpass

      Die Ausgabe vergleichst du mit dem was in der Datenbank steht.

      Wird noch salt oder anderes zusätzlich verwendet wird es etwas aufwändiger das Encrypted Password zu erzeugen.

      Hier wird crypt mit einem salt verwendet:

      $sCryptstring = crypt($sPassword,$row->{$sPasswordTableField});

      “$row->{$sPasswordTableField}” ist das salt. (http://dev.perl.org/perl6/rfc/208.html)

      Sobald du herrausgefunden hast, wie das Passwort erzeugt wird von phpbb md5, crypt oder etwas anderes und welcher salt verwendet wird, baust du das ganze wie oben mit einem kleinen perl-skript nach.

      Danach baust du das in das Orginal-Skript ein. So kannst du das Passwort dann auch durch Jabber ändern lassen.

      Gruß

      Sebastian

  8. Hi Andreas,
    du musst im Script noch die Funktion aktivieren:
    use Digest::MD5 qw(md5 md5_hex md5_base64);

    Ich habe auch schon crypt und encrypt durch md5 ersetzt, aber leider klappt das nicht.
    eJabberd gibt mir zwar ein error aus, aber damit kann ich nichts anfangen, in meine Kommentar vom 8 Juli kannst du einen Auszug davon sehen. Leider finde ich sonst keine weiteren Logs.
    @Sebastian: Was muss man in deinem Script hinzufügen das STDERR in ein log schreibt?
    Philipp

    1. Hi Philipp,

      hm du hast recht, ein paar Log-Einträge wären ganz sinnvoll.

      Schau dir dazu doch mal:

      http://perldoc.perl.org/Sys/Syslog.html

      oder vielleicht besser mit log4perl:


      http://www.linux-magazin.de/Heft-Abo/Ausgaben/2003/01/Wachsame-Schlaefer

      alternativ kann man natürlich mit Perl auch direkt Log-Files schreiben:

      open(LOG,”logfile”) or die “Unable to open logfile:$!\n”;
      while(){
      print if /\berror\b/i;
      }
      close(LOG);

      oder du gibst einen print nach STDERR:

      print { $OK ? STDOUT : STDERR } “Log-Entry\n”;

      Gruß

      Sebastian

  9. Hallo,

    @Philipp
    Danke für den Tipp

    @Sebastian
    Ich kenne mich bisher überhaupt nicht mit Skriptprogrammierung aus. Kann lediglich ein paar Schritte nachvollziehen.
    Da muss ich leider passen und warten bis jemand mit etwas Erfahrung etwas funktionsfähiges geschrieben hat.

  10. Muss außer
    {auth_method, external}.
    {extauth_program, “/etc/ejabberd/auth_mysql.pl”}
    noch etwas angepasst werden?- Zum Bsp in der ejabberd.conf unter “DATABASE SETUP”?-Muss hier nun ein mysql-server ausgewählt werden oder ist die Authentifizierung von der Datenbank unabhängig?

  11. Hallo,
    ich habe testweise das Skript und eine Datenbank verwendet.
    Hat auch erst wunderbar funktioniert, bis ich ein update von debian lenny auf sqeeze gemacht habe.
    Dabei ist ejabberd von Version 2.0.1-6 zu 2.1.5-3 geworden.
    Nun bekomme ich folgende Fehlermeldung:
    =ERROR REPORT==== 2011-02-09 22:22:43 ===
    E(:extauth:124) : extauth call ‘[“auth”,”*name*”,”*hostname*”,
    “*password*”]’ didn’t receive response

    Was hat sich denn an der Authentifizierung geändert? -Benötigt ejabberd jetzt einen anderen Rückgabewert?

  12. Huhu,

    unter welcher Lizenz steht das Script denn? Darf ich es (unter Angabe Deines Namens als Originalautor) wieder veröffentlichen?

    Danke!
    Jakob

  13. Hallo Jakob,

    ich hab nichts dagegen. Wenn du einen Link auf diesen Eintrag machst, wäre das natürlich toll.

    Gruß

    Sebastian

  14. Hi,

    ich habe vor mich mithilfe deines Skriptes an einen externen mysql server zu verbinden. Der mysql server läuft auf einem anderen host als der ejabberd server.
    In deinem skript kann ich zwar einen host eintrage, dieser wird aber nirgens im code benutzt.

    Ich habe schon verschiedene dinge in der “DBI->connect(‘DBI:mysql” zeile versucht, aber entweder verbindet er sich weiterhin auf “localhost” oder es erscheint nur ein “%” an stelle des servernamen.

    mit dem “mysql” programm und den selben login/datenbank-daten funktioniert es problemlos!

    Danke im voraus 🙂

    Denis

  15. Hi,

    hier ist wohl ein kleiner Fehler im connect:

    Versuche es mal mit:

    $connect = DBI->connect($sDatabaseHost, $sDatabaseName, $sDatabaseUser, $sDatabasePass) || die “Could not connect to database: $DBI::errstr”;

    Gruß

    Sebastian

  16. Hi !

    I got this error when I start Ejabberd using your script , this error heppens with many scripts too.

    this is the error :

    :extauth:146) : extauth script has exitted abruptly with reason ‘normal’

    Any idea ?

    Thank you

    1. @nrzi I’ve had the same error. It has to do with your perl modules. Put your ejabberd into debug mode (ejabberd.cfg) and execute ejabberd live (ejabberdctl live) to see if you have the same error. Mine was:

      “=ERROR REPORT==== 15-Jun-2013::19:28:21 ===
      C(:extauth:146) : extauth script has exitted abruptly with reason ‘normal’
      Can’t locate DBI.pm in @INC […]
      and
      Can’t locate DBD/mysql.pm in @INC

      To fix it just install the needed perl modules DBI and DBD::mysql. e.g. by using your package manager or by using the following commands:

      # perl -eshell -MCPAN
      cpan> install DBI
      cpan> install DBD::mysql

      That should fix it. Hope I could help!
      – dex

Schreibe einen Kommentar

eMail-Benachrichtigung bei weiteren Kommentaren.
Auch möglich: Abo ohne Kommentar.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.