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 (1665 Downloads )
Now make the script executeable:
chmod +x /etc/ejabberd/auth_mysql.pl
Noby
5 Feb 2009Als 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.
sebastian
5 Feb 2009Hi,
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.
sebastian
15 Sep 2009Nachtrag:
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.
Philipp
7 Jul 2010Hi 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!
Philipp
8 Jul 2010Hi 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
Philipp
11 Jul 2010Hallo 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
sebastian
12 Jul 2010Hallo,
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
Philipp
12 Jul 2010Hi 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?
sebastian
29 Jul 2010Hi,
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
Andreas
5 Dez 2010Hallo 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
sebastian
6 Dez 2010Hallo 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
Andreas
7 Dez 2010Hallo 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.
sebastian
7 Dez 2010Hallo,
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
Philipp
7 Dez 2010Hi 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
sebastian
7 Dez 2010Hi 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
Andreas
7 Dez 2010Hallo,
@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.
Benjamin
29 Jan 2011Muss 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?
sebastian
7 Feb 2011Nein {auth_method, external} verlagert die komplette Authentifizierung auf das Skript.
Die Datenbankeinstellungen in der ejabberd.conf sind für die integrierte MySQL-Authentifizierung gedacht.
Siehe dazu https://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver
(Kommentar oben von Noby)
Andreas
11 Feb 2011Hallo,
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?
Jakob Lenfers
22 Apr 2011Huhu,
unter welcher Lizenz steht das Script denn? Darf ich es (unter Angabe Deines Namens als Originalautor) wieder veröffentlichen?
Danke!
Jakob
sebastian
26 Apr 2011Hallo Jakob,
ich hab nichts dagegen. Wenn du einen Link auf diesen Eintrag machst, wäre das natürlich toll.
Gruß
Sebastian
Denis
29 Jul 2011Hi,
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
sebastian
1 Aug 2011Hi,
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
Pingback: jabber und ispconfig - Howtoforge Forum
nrzi
10 Mai 2013Hi !
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
dex
15 Jun 2013@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