Neues Modul: 96_allowedLDAP

Begonnen von _Markus_, 03 Oktober 2017, 12:22:08

Vorheriges Thema - Nächstes Thema

_Markus_

Hallo zusammen,

ich habe eine Erweiterung des allowed Moduls geschrieben, die gegen ein LDAP Verzeichnis authentifiziert und authorisiert.

Gründe hierfür

  • Per user eigene allowed commands und devices pflegen, insb. für user, die aus dem Internet zugreifen dürfen: Alexa, IFTTT, GeoFencingApp, ...
  • LDAP kennenlernen, mögliche Erweiterung bzgl. 2-Faktor Authentifizerung (z.B. Authelia).

Gründe, die dagegen sprechen

  • LDAP ist eine Kanone für den Spatzen FHEM.
  • Das FHEM Interface dient der Konfiguration, nicht den Bedienung aus dem Internet.
  • weitere...

Achtung: Das Modul funktioniert zwar, befindet sich aber noch im alpha Stadium. Ich veröffentliche es hier, da ich mir Feedback und Unterstützung erhoffe, insb. was die Sicherheit angeht. Selbstverständlich übernehme ich keine Verantwortung für die Absicherung dritter FHEM Instanzen.

Nun zum Modul:

Basics

  • Als Basis dient Rudis allowed Modul, dass ich in Teilen 1zu1 wiederverwende.
  • Da der Teil der LDAP Authentifizierung nicht sonderlich groß ist, könnte man allowed und allowedLDAP auch zusammenführen - da bin ich emotionslos.
  • Das Modul nutzt in allowedLDAP_Authenticate eine BasicAuth Maske zur Erfragung von Nutzer und Passwort.
  • Das Modul nutzt einen LDAP "admin" Account um den Nutzer im Verzeichnis zu suchen - in einer definierten SearchBase (ein LDAP Verzeichnis ist ein Baum).
  • Wird der Nutzer gefunden, versucht das Modul sich mit ihm erneut am LDAP Server zu authentifizieren. Funktioniert das, ist der Login-Versuch erfolgreich abgeschlossen.
  • Nach erfolgter Authentifizierung werden die LDAP-Attribute allowedCommands und allowedDevices in FHEM pro User hinterlegt (s.u.).
  • Bei erneutem Seitenaufruf wird das BasicAuth secret mit dem gemerkten Hash abgeglichen um erneutes abfragen des LDAP Servers zu vermeiden.
  • In der allowedLDAP_Authorize Methode wird der Command und das Device mit den hinterlegten Attributen allowedCommands und allowedDevices (s.u.) abgeglichen und entsprechend entschieden.
  • Das Modul lässt sich aktuell nur auf FHEMWEBs anwenden, nicht auf Telnet.
  • Der BasicAuth set-Command ist verschwunden, stattdessen gibt es diverse Attribute um den LDAP Server zu definieren (s.u.).
  • Ein neuer set-Command erlaubt das Ausloggen aller User.

Achtung allowedDevices: Das Verhalten von allowedDevices habe ich geändert. Hier kann nun eine DeviceSpec angegeben werden. Dies erschien mir sinnvoll um insb. auch auf Devices in einem bestimmten Raum abzugleichen.


Implementierung (bitte challengen!)

  • Da es keinen eindeutigen Client-Hash zu geben scheint (ggf. meine Unwissenheit), sondern dieser pro Socket-Verbindung (Port) neu erstellt wird, können leider keine Nutzer-spezifischen Informationen im Client-Hash hinterlegt werden.
  • Daher werden die allowedCommands und allowedDevices im Hash des allowedLDAP Geräts abgelegt, jeweils mit dem BasicAuth secret als Prepend.
  • Nun muss der allowedLDAP_Authorize nur das secret bekannt gemacht werden. Daher wird dieses in der allowedLDAP_Authenticate jeweils in den Client-Hash geschrieben. Das erscheint mir nicht sehr elegant - lieber wäre mir ein User-Hash.

Konfiguration
Es gibt in FHEM 4 Attribute für das allowedLDAP Device:

  • ldapServer: Host/IP des LDAP Servers, z.B.: localhost oder 127.0.0.1
  • ldapSearchBase: Knoten des LDAP Baums ab dem abwärts nach dem User gesucht wird. Kann z.B. eine Gruppe sein: cn=fhem,dn=example,dn=com
  • ldapBindDN: User, der nach den FHEM Nutzern im LDAP Server suchen darf, z.B. cn=admin,dn=example,dn=com
  • ldapBindDNPassword: Passwort des Users (s.o.).

Es muss natürlich ein LDAP Server aufgesetzt werden. Ich habe slapd genutzt. HowTos dazu gibt es jede Menge.
(https://www.howtoforge.com/how-to-install-openldap-server-on-debian-and-ubuntu)

Um den LDAP Server um die benötigten fhem Attribute zu erweitern, muss ein entsprechendes Schema angelegt werden.
# fhem.ldif
#       depends upon core.ldif
dn: cn=fhem,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: fhem
olcAttributeTypes: {0}( 1.3.6.1.4.1.42.2.27.4.1.90 NAME 'allowedCommands' DESC 'A comma
separated list of commands allowed from the matching frontend (see validFor). If set
to an empty list , (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.' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: {0}( 1.3.6.1.4.1.42.2.27.4.1.91 NAME 'allowedDevices' DESC 'A comma
separated list of device names which can be manipulated via the matching frontend
(see validFor).' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: {1}( 1.3.6.1.4.1.42.2.27.4.1.15 NAME 'fhemRepositoryId' DE
SC 'Repository ids of interfaces implemented by a CORBA object' EQUALITY caseExactMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcObjectClasses: {0}( 1.3.6.1.4.1.42.2.27.4.2.90 NAME 'fhem' DESC 'FHEM' SUP top
AUXILIARY MAY ( allowedCommands $ allowedDevices ) )


Achtung: Dieses Schema nutzt die OIDs des Corba Schemas. Davon wird im Internet stark abgeraten. Stattdessen kann man sich kostenlos eigene OIDs erstellen lassen. Bitte dazu Google bemühen. Fürs Testen tuns auch obige OIDs.

Zum Hinzufügen des Schemas einfach wie folgt:
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/fhem.ldif

Als FHEM Nutzer nutze ich im LDAP-Server die PosixAccount Vorlage (Schemata: inetOrgPerson (strukturell), posixAccount, fhem).
Wie oben beschrieben können die Attribute allowedCommands und allowedDevices hier direkt am User im LDAP gesetzt werden nachdem die FHEM objectClass hinzugefügt worden ist, z.B.: allowedCommands: set-user und allowedDevices: room=Alexa.


TODOs / Ideen / Kritik

  • TODO: Timeout für Logins entsprechend Rudis Cookie Logik.
  • Idee: allowedCommands und allowedDevices an LDAP Gruppen statt an Usern.
  • Idee: User/Gruppen-spezifische FHEMWEB Instanzen (das geht leider ziemlich quer zur aktuellen Implementierung).
  • Kritik: Speichern der secrets im Client Hash, speichern der secrets im Device Hash, kein User Hash.
  • ...


Wie gesagt würde ich mich über Feedback, Anregungen und Mithilfe freuen.

Viele Grüße
Markus

rudolfkoenig


CoolTux

Ah ich weiß wieso Rudi so grinst, darauf wartet er schon eine ganze Weile. Eine Erweiterung des allowed Modules auf LDAP oder DB Abfragen.  ;D
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

_Markus_

So hab ich das auch interpretiert  ;)

micronet24

auch wenn dieses Modul schon ein paar Tage älter ist, habe ich es die Tage mal in Betrieb genommen, um die Warnung im FHEM zu beheben und es an die bestehende Nutzerdatenbank anzubinden. Die Familie freut sich, sich kein weiteres Passwort merken zu müssen.

Dabei habe ich gleich noch ein paar Anpassungen implementiert...

LDAP OIDs

Die OIDs der Attribute waren alle irgendwo im SUN Namespace (1.3.6.1.4.1.42) verortet. Eine kurze Recherche hat ergeben, das der FHEM e.V. bereits eine PEN (58122) und damit auch einen eigenen Namespace (1.3.6.1.4.1.58122) besitzt. Ich habe die Attribute und ObjectClass mal dahin verschoben und (mangels öffentlich dokumentierter Struktur - ich hab zumindest nichts gefunden) einen sinnvoll erweiterbaren Unterbaum aufgespannt. Ich würde das in der Form trotzdem eher als Vorschlag verstehen und Anpassungen gerne vornehmen.

Aus gemachten Erfahrungen (clashing namespaces) hab ich die Attribute mit dem Prefix "x-fhem-" versehen. Da sich das Verhalten subtil geändert hat (s.u.) zwingt das ggf. aber sowieso dazu, bestehende Regeln zu überprüfen.

LDAP Verbindung

In den meisten Konfigurationen kann man aus dem Nutzernamen ziemlich direkt auf die zugehörigen DN im ldap schließen (irgendwas in der Form von "uid=<Nutzer>,ou=People,dc=domain"). Mit Hilfe des neuen FEHM-Attributes ldapUserMapping ist das jetzt auch direkt möglich - und erspart so das Einrichten eines FHEM-Nutzers im ldap für die Suche (der Nutzer kann sich mit seinem Passwort direkt am Server authentifizieren und seinen eigenen Eintrag auslesen).

Net::LDAP

Für die Kommunikation zum Server wird das Modul nach wie vor gebraucht. Ist es nicht vorhanden, schreibt allowedLDAP eine Meldung ins log und tut effektiv nichts mehr.

Da die Kommunikation inzwischen nur noch aus einer einzigen Funktion erfolgt, könnte man das laden und überprüfen auch dorthin verschieben - die Warnung würde nur noch erscheinen, wenn die Authentifizierung verwendet werden soll. Ich kann mich nur nicht für ein Standardverhalten in diesem Fall entscheiden. Die sichere Variante wäre jeden Zugriff zu blockieren - und nur über direkten Zugriff auf den Server das System wieder steuern zu können. Die Alternative wäre jeden Zugriff zuzulassen und den unaufmerksamen Administrator in falscher Sicherheit zu wiegen (geht ja alles...).

Verhaltensanpassung

Mit dem alten Modul war jeglicher Zugriff gesperrt, wenn ein LDAP-Attribut für den Nutzer nicht vorhanden war, und jeder Zugriff erlaubt, wenn es vorhanden aber leer war. Sobald etwas darin stand (als Komma-separierte Liste) wurden dann aber nur diese Elemente zugelassen. Zum einen fand ich das Verhalten verwirrend, zum andern erzeugt es einen hohen administrativen Aufwand, da für jeden Nutzer das wahrscheinlichere Standardverhalten (er darf FHEM nutzen) an mehreren Stellen aktiviert werden musste.

Statt dessen gibt es jetzt das folgende Verhalten:
  • nur wenn das Objekt des Nutzers im LDAP die objectClass=fhem enthält, darf er sich auch anmelden
  • sind die entsprechenden `x-fhem-allowed*` Attribute nicht definiert, darf er alles
  • gibt es nur ein leeres Attribut, sind alle Zugriffe des Typs verboten (aber ehrlich: warum darf sich der Nutzer anmelden, wenn er nichts machen kann?)
  • Zugriff auf mehrere Geräte / Kommandos werden über mehrfach spezifizierte ldap-attribute erzeugt (wie sonst auch im LDAP üblich). im FHEM-Modul kommen die Einträge dann als Liste an (und man braucht nicht mehr über Sonderzeichen, Feldtrenner und String-handling nachdenken)

Dokumentation

Für die Commandref dürften die nötigen Informationen jetzt auch direkt aus dem Modul ausgelesen werden können. (OT: Ich bin wahrscheinlich nur zu blind die Information zu finden, aber wie kann man die Commandref lokal aus den Modulen neu erzeugen?)

Räume

Um einfacher ganze Räume für bestimmte Nutzer freizugeben oder zu sperren, gibt es neu das LDAP-Attribut x-fhem-allowedRooms - mit einem analogen Verhalten zu x-fhem-allowedCommands und x-fhem-allowedDevices.

Ich hoffe jetzt einfach mal, dass das ganze auch anderen hilft und nicht nur meiner Selbstbespassung gedient hat. Ansonsten würde ich mich Markus' Bemerkung zu Feedback/Anregung/Mithilfe anschließen.

Die einzelnen Änderungen am Modul selber können im übrigen auch über https://git.dresden.micronet24.de/FHEM/allowedLDAP gefunden werden.

_Markus_