Hallo zusammen,
das Modul
FHEMWEB bietet ja die Möglichkeit zur Authentifizierung (Attribut
basicAuth). Auf einer FritzBox gibt es die Möglichkeit, Benutzernamen und Passwort vom System (der FritzBox) prüfen zu lassen und so auf BASE64-kodierte Zugangsdaten zu verzichten. Ich hätte dieses Feature gerne auf einem Raspberry Pi. Ich habe gelesen, dass es dafür unter Linux die
Pluggable Authentication Modules (PAM) und ein passendes Perl-Modul gibt. Folgende Funktion soll die Authentifizierung übernehmen:
use Authen::PAM;
sub authenticate($$) {
my $service = "login";
my $username = shift;
my $password = shift;
sub fill_credentials {
my @res;
while ( @_ ) {
my $code = shift;
my $msg = shift;
my $ans = "";
$ans = $username if ($code == PAM_PROMPT_ECHO_ON() );
$ans = $password if ($code == PAM_PROMPT_ECHO_OFF() );
push @res, (PAM_SUCCESS(), $ans);
}
push @res, PAM_SUCCESS();
return @res;
}
my $pamh;
ref($pamh = new Authen::PAM($service, $username, \&fill_credentials)) ||
die "Error code $pamh during PAM init!";
return $pamh->pam_authenticate;
}
Wenn ich die Funktion als User pi (ohne sudo) ausführe, erhalte ich
PAM_SUCCESS. Wenn ich sie als User fhem ausführe, erhalte ich
PAM_PERM_DENIED.
Kann mir jemand sagen:
- Warum?
- Wie kann ich das ändern?
Ich bin etwas weiter. In /var/log/auth.log fand ich
pam_securetty(login:auth): cannot determine user's tty
Deshalb habe ich mein Skript wie folgt erweitert:
use Authen::PAM;
use POSIX qw(ttyname);
my $service = "login";
my $username = shift;
my $password = shift;
my $tty_name = ttyname(fileno(STDIN));
...
$res = $pamh->pam_set_item(PAM_TTY(), $tty_name);
$res = $pamh->pam_authenticate;
...
Damit erhalte ich im Log jetzt
pam_securetty(login:auth): access denied: tty '/dev/pts/1' is not secure !
pam_unix(login:auth): check pass; user unknown
Nach Eintrag von
pts/1
in /etc/securetty verschwindet die erste Meldung. Bleibt noch die zweite...
FHEM ist ein Daemon, und hat kein tty: ich vermute du musst einen Weg ohne tty finden.
Ich habe in einem StackExchange-Artikel (http://unix.stackexchange.com/questions/66392) gelernt, dass meine Idee nicht funktionieren wird, solange der ausführende Prozess keine root-Rechte hat. Der Artikel verweist aber auf einen anderen Lösungsansatz basierend auf einem Tool namens expect. Ich habe daraufhin ein Skript geschrieben, dass die Authentifizierung aus FHEM heraus erfolgreich durchführt.
Inhalt des Skriptes:
#!/usr/bin/expect -f
log_user 0
set username [lindex $argv 0]
set password [lindex $argv 1]
if { $username == "" || $password == "" } {
puts "Usage: <username> <password>\n"
exit 1
}
spawn su -l $username -c "echo OK"
expect ":"
send "$password\n"
expect {
"OK" { send_user "OK" }
"su:" { send_user "NOK" }
timeout { send_user "Timeout" }
eof { send_user "EOF" }
}
Das Skript habe ich unter /home/pi/auth.expect gespeichert und mittels
chmod +x /home/pi/auth.expect
ausführbar gemacht.
Für die Ausführung des Skriptes benötigt man das Tool expect, das sich z.B. durch
sudo apt-get install expect
installieren lässt.
In der FHEM-Konfiguration kann es durch Setzen von
attr WEB basicAuth { `/home/pi/auth.expect $user $password` eq "OK" }
verwendet werden.
Nach ein paar Minuten Einsatz habe ich festgestellt, dass die Reaktion der Weboberfläche dadurch sehr träge geworden ist. Die Authentifizierung wird offenbar beim Laden jeder HTTP-Ressource durchgeführt, also ein paar mal pro Klick. Das dauert dann natürlich. Ich glaube nicht, dass ich das in dieser Form nutzen möchte. :-\
Du kannst einen lokalen reverse Proxy auf der Fhem Kiste einsetzen, mit einem Apache bist du da z.B. deutlich flexibler was die Authentication anbelangt und könntest die Anmeldedaten aus verschiedenen Quellen beziehen, sowie wird es dann auch nur einmalig beim Login ausgeführt.
Siehe z.B. => http://forum.fhem.de/index.php/topic,29909.0.html
Danke, das sieht interessant aus.