############################################## # $Id$ package main; use strict; use warnings; ##################################### sub allowed_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "allowed_Define"; $hash->{AuthorizeFn} = "allowed_Authorize"; $hash->{AuthenticateFn} = "allowed_Authenticate"; $hash->{AttrFn} = "allowed_Attr"; $hash->{AttrList} = "disable:0,1 validFor allowedCommands allowedDevices ". "basicAuth basicAuthMsg password globalpassword"; $hash->{UndefFn} = "allowed_Undef"; } ##################################### sub allowed_Define($$) { my ($hash, $def) = @_; my @l = split(" ", $def); if(@l > 2) { my %list; for(my $i=2; $i<@l; $i++) { $list{$l[$i]} = 1; } $hash->{devices} = \%list; } $auth_refresh = 1; readingsSingleUpdate($hash, "state", "active", 0); return undef; } sub allowed_Undef($$) { $auth_refresh = 1; return undef; } ##################################### # Return 0 for don't care, 1 for Allowed, 2 for forbidden. sub allowed_Authorize($$$$) { my ($me, $cl, $type, $arg) = @_; return 0 if($me->{disabled}); return 0 if($me->{validFor} && $me->{validFor} !~ m/\b$cl->{SNAME}\b/); if($type eq "cmd") { return 0 if(!$me->{allowedCommands}); return ($me->{allowedCommands} =~ m/\b$arg\b/) ? 1 : 2; } if($type eq "devicename") { return 0 if(!$me->{allowedDevices}); return ($me->{allowedDevices} =~ m/\b$arg\b/) ? 1 : 2; } return 0; } ##################################### # Return 0 for authentication not needed, 1 for auth-ok, 2 for wrong password sub allowed_Authenticate($$$$) { my ($me, $cl, $param) = @_; return 0 if($me->{disabled}); return 0 if($me->{validFor} && $me->{validFor} !~ m/\b$cl->{SNAME}\b/); my $aName = $me->{NAME}; if($cl->{TYPE} eq "FHEMWEB") { my $basicAuth = AttrVal($aName, "basicAuth", undef); return 0 if(!$basicAuth); my $FW_httpheader = $param; my $secret = $FW_httpheader->{Authorization}; $secret =~ s/^Basic //i if($secret); my $pwok = ($secret && $secret eq $basicAuth); # Base64 if($secret && $basicAuth =~ m/^{.*}$/) { eval "use MIME::Base64"; if($@) { Log3 $aName, 1, $@; } else { my ($user, $password) = split(":", decode_base64($secret)); $pwok = eval $basicAuth; Log3 $aName, 1, "basicAuth expression: $@" if($@); } } return 1 if($pwok); my $msg = AttrVal($aName, "basicAuthMsg", "FHEM: login required"); $cl->{".httpAuthHeader"} = "HTTP/1.1 401 Authorization Required\r\n". "WWW-Authenticate: Basic realm=\"$msg\"\r\n"; return 2; } if($cl->{TYPE} eq "telnet") { my $pw = AttrVal($aName, "password", undef); if(!$pw) { $pw = AttrVal($aName, "globalpassword", undef); $pw = undef if($pw && $cl->{NAME} !~ m/^telnet:127.0.0.1/); } return 0 if(!$pw); return 2 if(!defined($param)); if($pw =~ m/^{.*}$/) { my $password = $param; my $ret = eval $pw; Log3 $aName, 1, "password expression: $@" if($@); return ($ret ? 1 : 2); } return ($pw eq $param) ? 1 : 2; } return 0; } sub allowed_Attr(@) { my ($type, $devName, $attrName, @param) = @_; my $hash = $defs{$devName}; my $set = ($type eq "del" ? 0 : (!defined($param[0]) || $param[0]) ? 1 : 0); if($attrName eq "disable") { readingsSingleUpdate($hash, "state", $set ? "disabled" : "active", 1); if($set) { $hash->{disable} = 1; } else { delete($hash->{disable}); } } elsif($attrName eq "allowedCommands" || # hoping for some speedup $attrName eq "allowedDevices" || $attrName eq "validFor") { if($set) { $hash->{$attrName} = join(" ", @param); } else { delete($hash->{$attrName}); } } elsif(($attrName eq "basicAuth" || $attrName eq "password" || $attrName eq "globalpassword") && $type eq "set") { foreach my $d (devspec2array("TYPE=(FHEMWEB|telnet)")) { delete $defs{$d}{Authenticated} if($defs{$d}); } } return undef; } 1; =pod =begin html
define <name> allowed <deviceList>
define allowedWEB allowed
attr allowedWEB validFor WEB,WEBphone,WEBtablet
attr allowedWEB basicAuth { "$user:$password" eq "admin:secret" }
attr allowedWEB allowedCommands set,get
define allowedTelnet allowed
attr allowedTelnet validFor telnetPort
attr allowedTelnet password secret
, (i.e. comma only)
then no comands are allowed. If set to get,set
, then only
a "regular" usage is allowed via set and get, but changing any
configuration is forbidden.
attr allowedWEB basicAuth { "$user:$password" eq "admin:secret" }
attr allowed_tPort password secret
attr allowed_tPort password {"$password" eq "secret"}
define <name> allowed <deviceList>
define allowedWEB allowed
attr allowedWEB validFor WEB,WEBphone,WEBtablet
attr allowedWEB basicAuth { "$user:$password" eq "admin:secret" }
attr allowedWEB allowedCommands set,get
define allowedTelnet allowed
attr allowedTelnet validFor telnetPort
attr allowedTelnet password secret
get,set
gesetzt ist, dann sind in dieser
Frontend keine Konfigurationsänderungen möglich, nur
"normale" Bedienung der Schalter/etc.
$ echo -n fhemuser:secret | base64
ZmhlbXVzZXI6c2VjcmV0
fhem.cfg:
attr WEB basicAuth ZmhlbXVzZXI6c2VjcmV0
attr allwedWEB basicAuth { "$user:$password" eq "admin:secret" }
attr allowed_tPort password secret
attr allowed_tPort password {"$password" eq "secret"}
perl fhem.pl localhost:7072 secret "set lamp on"