Modularisierung der Authorisierung/Authentifizierung

Begonnen von rudolfkoenig, 29 Dezember 2015, 20:39:07

Vorheriges Thema - Nächstes Thema

rudolfkoenig

Angeregt von diese und jene Diskussion habe ich die Authorisierung (frueher allowedCommands) und Authentifizierung (basicAuth/password) Modularisiert, wie das hier schon angedeutet wurde.

Falls ein Modul eine AuthorizeFn anbietet, und eine Instanz dieses Moduls existiert, dann wird diese Funktion
- vor dem Ausfuehren jedes Befehls, was direkt von einem Frontend stammt, mit dem Hash des Frontends und dem Befehl aufgerufen. Sie kann 0 (interessiert mich nicht), 1 (erlaubt) oder 2 (verboten) zurueckliefern. Funktionalitaet wie der bisherige allowedCommands.
- danach (wieder nur "Frontend" Befehle), falls ein Befehl devspec2array verwendet, wird diese Funktion (mit anderen Parametern) fuer jedes zutreffende Geraet einzeln aufgerufen. Funktionalitaet wie das vorgeschlagene allowedDevices.

Falls ein Modul eine AuthenticateFn anbietet, und eine Instanz dieses Moduls existiert, dann wird diese Funktion von FHEMWEB und vom telnet aufgerufen. Rueckgabewerte aehnlich: 0: keine Authentifizierung notwendig, 1: Authentifizierung ok, 2: Authentifizierung fehlgeschlagen.

Als Beispiel bzw. zur Bewahrung der bisherigen Funktionalitaet habe ich 96_allowed.pm gebaut, der die bisherigen Attribute allowedCommands, allowedDevices, basicAuth, passwort in sich vereint.

Falls ein Benutzer einen dieser Attribute gesetzt hat, dann wird fuer die betroffenen Instanzen jeweils eine neue allowed_<alteName> Instanz angelegt (validFor wird entsprechend gesetzt) und mit den Attributen versehen.

Ich vermute durch den Umbau ist allowedCommands in yowsup.pm erstmal wirkungslos geworden, bitte anpassen. Bei FLOORPLAN bin ich nicht ganz sicher, ich vermute es funktioniert noch. Ich bitte um Feedback.

justme1968

32_yowsup.pm habe ich gerade nachgezogen.

in dem zusammenhang ist mir aufgefallen das es ausser featurelevel (das hier auch nicht verwendet wird) keine möglichkeit gibt festzustellen ob das gerade eingesetzte fhem eine bestimmte funktionalität unterstützt. d.h. es ist nicht möglich das ein modul zumindest für die Übergangszeit das alte und das neue api unterstützt. ich vermute für yowsup ist das erst mal kein problem da ich der einzige bin der ein altes fhem mit einem neuen modul einsetzt. in anderem zusammenhang könnte das aber mal probleme machen.


kann es sein das die mehr oder weniger zufällige reihenfolge in der die AuthorizeFn und AuthenticateFn aufgerufen werden es unmöglich machen mit einer definierten allow/deny reihenfolge zu arbeiten wen ein modul das implementieren möchte?

die in meinem patch vorgeschlagenen änderungen an list, jsonlist2 und xmllist um die 'verbotenen' devices auch dort unsichtbar zu machen sind ja jetzt erst mal nicht mit drin. hat du eine idee wie man das halbwegs generell umsetzen kann?
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

justme1968

das problem mit der aufruf reihenfolge kann man (etwas) entschärfen wenn man in Authorized die liste aller AuthorizeFn auch im allow fall bis zu ende durchgeht. d.h. nur im verboten fall vorzeitig abbricht.

beispiel:

für die fehmweb instanz ist ein zugehöriges allowed definiert und ein modul bringt selber noch mal eigenes allowed mit das stärkere einschränkungen hat. es hängt jetzt von der reihenfolge ab ob das zum modul gehörende allowed überhaupt zum zuge kommt.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

viegener

Zitat von: rudolfkoenig am 29 Dezember 2015, 20:39:07
Als Beispiel bzw. zur Bewahrung der bisherigen Funktionalitaet habe ich 96_allowed.pm gebaut, der die bisherigen Attribute allowedCommands, allowedDevices, basicAuth, passwort in sich vereint.

Falls ein Benutzer einen dieser Attribute gesetzt hat, dann wird fuer die betroffenen Instanzen jeweils eine neue allowed_<alteName> Instanz angelegt (validFor wird entsprechend gesetzt) und mit den Attributen versehen.

Klingt ja spannend. Ich würde ja vorschlagen meinen ursprünglichen FHEMWeb-Patch so umzubauen, dass er in 96_allowed passt. So lässt er sich wenig invasiv umsetzen (im wesentlichen allowed_Authenticate und vermutlich noch allowed_Attr). Ich frage lieber vorher, damit ich den patch nicht umsonst erstelle...

Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

Benni

Hallo Rudi,

wollte mir eben die Doku zu allowed in der Commandref anschauen.
Die habe ich schließlich "gut versteckt" hinter der Doku zum 2. at gefunden ;)


rudolfkoenig

Zitatzufällige reihenfolge in der die AuthorizeFn und AuthenticateFn aufgerufen werden
Die Funktionen werden in der Reihenfolge der Instanznamen aufgerufen. Ich habe kein Problem ein zusaetzliches Attribut einzufuehren, meine z.Zt., dass es nicht notwendig ist.

Zitatdie liste aller AuthorizeFn auch im allow fall bis zu ende durchgeht
Wenn man das Implementiert, dann ist 1 als Rueckgabewert von AuthorizeFn sinnlos. Oder andersrum: dein Szenario kann man dadurch implementieren, dass man in AuthorizeFn nur 0 oder 2 zurueckliefert. Das habe ich jetzt in allowed umgesetzt.

Ich habe Authenticate angepasst, so dass bei Ablehnung so lange weitergefragt wird, bis einer der Module OK gibt. Hier funktioniert mit das Spiel 0 vs. 1 nicht, weil "keine Authentifizierung" ja ungleich "Authentifizierung nicht geklappt" ist.

Zitatlist, jsonlist2 und xmllist um die 'verbotenen' devices auch dort unsichtbar zu machen
Habs nachgezogen, danke fuer die Erinnerung. FHEMWEB bleibt unberuehrt davon, da muss man weiterhin mit hiddenroom herumspeilen.

ZitatIch würde ja vorschlagen meinen ursprünglichen FHEMWeb-Patch so umzubauen, dass er in 96_allowed passt.
Gerne, aber ich habe auch nichts dagegen, wenn das Feature in einem eigenstaendigen Modul implementiert wird.

ZitatDie habe ich schließlich "gut versteckt" hinter der Doku zum 2. at gefunden
Danke, habs korrigiert.

justme1968

mit mehr oder weniger zufällig meinte ich von den jeweiligen device namen abhängig :) das macht schon bei notify manchmal probleme.  ich glaube das ist bei so etwas wichtigen wie security falsch.

wenn der benutzer keine möglichkeit hat die reihenfolge zu beeinflussen sollte das verhalten umgekehrt sein. das erste ablehnen gilt und bei ok wird so lange weiter gemacht bis die liste durch ist.

das ist nicht sinnlos. wenn es nur ok gibt und die liste zu ende ist dann ist ok das endergebnis.

sonst kann man z.b. keine module über fhemweb oder telnet verwenden die eine striktere policy haben. siehe beispiel oben. das ok von fhemweb überschreibt alles.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Zitatdas ist nicht sinnlos. wenn es nur ok gibt und die liste zu ende ist dann ist ok das endergebnis.

Aber wenn kein ok von einem Modul gibt (nur ein "geht mich nichts an"), dann ist das Endergebnis doch auch ok. Insofern waere mit deiner Methode ok gleichwertig mit "geht mich nichts an".

justme1968

bei ok und bei geht mich nichts an bis zum ende weiter machen. bei nein sofort nein zurück geben.

wie oben im beispiel beschrieben:

sobald ein modul eine eigene (spezifischere) AuthorizeFn mit bringt wird diese nicht mehr ausgewertet sobald die allgemeine für fhemweb davor aufgerufen wird. was sie aus alphabets gründen sogar fast immer wird. WEB kommt halt ziemlich weit hinten.

es sollte aber so sein das modul spezifische auf jeden fall aufgerufen wird.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Wird doch: alle Auth-Module muessen 0/"geht mich nichts an" zurueckliefern, wenn sie zulassen wollen, dass andere Auth-Module ein Veto-Recht haben.

Sonst ist "ok" vom "geht mich nichts an" nicht zu unterscheiden. Oder anders: mit deinem Vorschlag muss auch das API geaendert werden, und AuthorizeFn darf nur "ok" oder "nicht ok" zurueckliefern. Wuerde nur die Funktionalitaet gegenueber jetzt einschraenken. Vielleicht ist es aber doch sinnvoll, damit ich nicht immer solche langen Argumentationsorgien abhalten muss :)

justme1968

lach. sag doch einfach ich habe recht :)

aber im ernst:

im web gibt es ein allowedCommands das ein set erlaubt. im modul gibt es ein spezifischeres allowed das nur set xy erlaubt.

das funktioniert nur wenn bei ok weiter gemacht wird.

ps: vielleicht ist es ganz unabhängig von dieser diskussion sinnvoll log meldungen einzubauen welches modul was zurück gegeben hat und in welcher reihenfolge sie aufgerufen wurden. sonst wird das debuggen auch für den anwender unter umständen schwierig.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

viegener

Zitat von: justme1968 am 30 Dezember 2015, 11:23:36
ps: vielleicht ist es ganz unabhängig von dieser diskussion sinnvoll log meldungen einzubauen welches modul was zurück gegeben hat und in welcher reihenfolge sie aufgerufen wurden. sonst wird das debuggen auch für den anwender unter umständen schwierig.

Absolut wichtig, ich befürchte sonst kann ein anwender uns nicht mal sinnvolle logs produzieren, mit denen die entwickler das problem nachvollziehen können. das sollte aber beim aufruf erfolgen, damit man das zentral ein/auschalten kann und auch die einträge standardisiert sind.
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

viegener

Zitat von: rudolfkoenig am 30 Dezember 2015, 10:28:55
Gerne, aber ich habe auch nichts dagegen, wenn das Feature in einem eigenstaendigen Modul implementiert wird.

Ich habe leider das Problem, dass die Cookie-Lösung sich so nicht realisieren lässt, da ja ein Header (set-cookie) NACH erfolgreicher Anmeldung gesetzt werden müsste. Aber .httpauthheader nur mitgeschickt wird wenn die Anmeldung notwendig ist und fehlt.

Der Cookie wird ja gesetzt wenn die Anmeldung erfolgreich war und der normale Inhalt (für den ersten Request) zurückgeht.
Könnte man den .httpauthheader auch in anderen Fällen mitsenden (sozusagen ein .httpauthtokenheader)
Alternative: Ein zusätzlicher .httpServerHeader, der auch von anderen Erweiterungen (nicht nur Auth gesetzt werden könnte)?
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

Loredo

Ich fände es besser eine echte formularbasierte Anmeldung zu haben.
BasicAuth lässt sich nicht mit Passwortmanagern wie 1Passwort verwenden.
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

Loredo

Als Alternative Anmeldemöglichkeit für zB um die GUI als MobileWeb.app inkl authentifizierung abspeichern zu können, sollte man sich auch per Auth-Token in der URI anmelden können (BasicAuth geht hier auch, ist aber umständlicher und nicht so schick vor allem wenn man ansonsten eine formularbasierte Authentifizierung macht). X509 Anmeldung ist zwar toller/schicker/sicherer, ist aber schwerer zu handhaben und werden wir wohl so bald nicht in Fhem direkt haben (wer will kanns ja nach wie vor über einen Reverse-Proxy wie bisher auch tun).


Gruß
Julian
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

Markus Bloch

Ich würde es besser finden wenn man Basic-Authentifizierung gegen Digest-Authentifizierung tauschen würde. Finde ich sicherheitstechnisch nicht wirklich prickelnd das Passwort im Klartext zu übertragen.

Viele Grüße

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

rudolfkoenig

Zitatsinnvoll log meldungen einzubauen
Habs gemacht. Es muss ja schliesslich einen Grund geben, auf schnelleren Hardware zu wechseln :)
Um es zu aktivieren muss verbose >= 4 fuer das Eingangsgeraet (telnetPort/WEB) gesetzt werden, global verbose wird nicht konsultiert.

ZitatKönnte man den .httpauthheader auch in anderen Fällen mitsenden
Habs eingebaut.

ZitatFinde ich sicherheitstechnisch nicht wirklich prickelnd das Passwort im Klartext zu übertragen.
Sinnvollerweise wird basicAuth nur in Verbindung mit HTTPS verwendet. Uebrigens habe ich mir die Muehe mit dieser Modularisierung deswegen gemacht, damit Andere sich auch verwirklichen koennen, also nur zu.

viegener

Zitat von: viegener am 30 Dezember 2015, 14:51:55
Der Cookie wird ja gesetzt wenn die Anmeldung erfolgreich war und der normale Inhalt (für den ersten Request) zurückgeht.
Könnte man den .httpauthheader auch in anderen Fällen mitsenden (sozusagen ein .httpauthtokenheader)
Alternative: Ein zusätzlicher .httpServerHeader, der auch von anderen Erweiterungen (nicht nur Auth gesetzt werden könnte)?

So jetzt habe ich den Patch neu erstellt und mit Firefox und Chrome getestet.
Allerdings ist doch eine Änderung in FHEMWeb erforderlich, da der Header auch bei erfolgreicher Authentifizierung (also beim ersten Request) mit gesendet wurde. Ich habe das Mitsenden in anderen Fällen dafür wieder auskommentiert, da der Header nur einmal mitgesendet werden muss (für meinen Fall). Deshalb wird der auch nach dem ersten Senden zurückgesetzt.
=> Das ist aber auch im Patch enthalten.

Es gibt an allowed ein Attribut basicAuthExpiry, dass es ermöglicht die basic Authentication nur einmal alle n Tage abzufragen. Dazu muss das Attribut auf den Wert n gesetzt werden. Die Beschreibung ist auch in der allowed-Doku enthalten.

Hoffe das passt jetzt?


Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

rudolfkoenig

ZitatHoffe das passt jetzt?
Nicht wirklich:
- Der Patch ist nicht auf 80 Zeichen formatiert :)
- fuer Datumsformatierung haben wir schon eine Funktion: FmtDateTimeRFC1123
- Die Authenticate-Erweiterung wurde nicht nur fuer diese Cookie-Implementierung gebaut, deswegen moechte ich den AuthHeader immer drin haben.
- mir passt nicht, dass basicAuth (und damit Benutzername/Passwort) als Cookie im Browser gespeichert werden, wo das jeder mit Zugriff zum Browser abschreiben, und in dem eigenen Browser mit einem laengerem Expiry einbauen kann. Wenn basicAuth folgenden Syntax hat:
{ CheckLDAP($user, $password) }
dann ist das nach einmaligen Abhoeren selbst nach Passwortaenderung anwendbar.
Wenn die Kommunikation nicht abhoerbar ist, dann stellt sich die Frage nach dem Sinn von einem Passwort.

Die ersten drei Punkte koennte ich selbst fixen, beim Letzten faellt mir nichts ein, was nicht Schlangenoel waere.

Vorschlag:
  attr basicAuthCookie days CookieText
Als Cookie wird statt basicAuth CookieText gesetzt, und der Benutzer wird in der Doku darauf hingewiesen, dass diese Methode nur "Schlangenoel" ist, da es nach Abhoeren von einem Hacker beliebig lange angewendet werden kann. Ich wollte das nicht direkt einbauen, da ich unsicher bin, ob es damit fuer dich noch relevant ist.

viegener

Zitat von: rudolfkoenig am 01 Januar 2016, 13:21:57
Nicht wirklich:
- Der Patch ist nicht auf 80 Zeichen formatiert :)
- fuer Datumsformatierung haben wir schon eine Funktion: FmtDateTimeRFC1123
- Die Authenticate-Erweiterung wurde nicht nur fuer diese Cookie-Implementierung gebaut, deswegen moechte ich den AuthHeader immer drin haben.
- mir passt nicht, dass basicAuth (und damit Benutzername/Passwort) als Cookie im Browser gespeichert werden, wo das jeder mit Zugriff zum Browser abschreiben, und in dem eigenen Browser mit einem laengerem Expiry einbauen kann. Wenn basicAuth folgenden Syntax hat:
{ CheckLDAP($user, $password) }
dann ist das nach einmaligen Abhoeren selbst nach Passwortaenderung anwendbar.
Wenn die Kommunikation nicht abhoerbar ist, dann stellt sich die Frage nach dem Sinn von einem Passwort.

Die ersten drei Punkte koennte ich selbst fixen, beim Letzten faellt mir nichts ein, was nicht Schlangenoel waere.

Vorschlag:
  attr basicAuthCookie days CookieText
Als Cookie wird statt basicAuth CookieText gesetzt, und der Benutzer wird in der Doku darauf hingewiesen, dass diese Methode nur "Schlangenoel" ist, da es nach Abhoeren von einem Hacker beliebig lange angewendet werden kann. Ich wollte das nicht direkt einbauen, da ich unsicher bin, ob es damit fuer dich noch relevant ist.

Ok, bevor ich den dritten Patch mache, sollten wir besser ein Design abstimmen


- Auf 80Zeichen begrenzen kann ich schon machen
- Die vorhandene Routine nehmen auch (die RFC-Nummern verwechselt deshalb habe ich die Routine nicht gefunden)
- Das mit dem Authenticate-Header immer ist kein grosses Problem, wobei es schön wäre irgendwie zu steuern, dass er nur einmal gesendet werden muss.

Zu Deinen Bedenken, das verstehe ich auch wenn ich nur einen basicAuth-Attribut mit statischem String kannte.
Ich sehe 2 Vorschläge:

a) Statt den Inhalt des Attributes basicAuth zu senden, könnte man ja auch den http-header senden, der ja sowieso bei jeder basicAuth-Anmeldung heute schon mitgeschickt wird nehmen?

b) Alternativ und etwas aufwändiger, wäre es eine Liste der Anmeldungen im allowed-Modul zu verwalten (mit Ablaufdatum) und dann im Cookie nur einen hash oder eine uuid zu versenden. Problem: relativ aufwändig (wg. Verwaltung für abgelaufene Sessions/Cookies) und eigentlich auch nicht wirklich sicherer, da ja immer noch ein basicAuth mit user/password übers Netz geht.

Ich würde vorschlagen Alternative a zu machen



-
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

Markus Bloch

#20
Hallo zusammen,

mit der neuen allowed-Implementierung habe ich hier erste Meldungen, dass damit Blocking-Calls nicht mehr funktionieren:

http://forum.fhem.de/index.php/topic,46498.msg383056.html#new
http://forum.fhem.de/index.php/topic,46256.msg383070.html#new
http://forum.fhem.de/index.php/topic,46515.0.html

Ich nehme mal an, dass dies daran liegt, dass in Blocking das allowed-Modul System nicht nachgezogen ist um eine telnet-Verbindung zu ermitteln.

Kann sich das mal jemand anschauen, da ich bei allowed noch nicht so ganz durchsteige.

Vielen Dank

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Markus Bloch

Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

rudolfkoenig

@Markus: habs gefixt, getestet und eingecheckt.

Markus Bloch

Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

rudolfkoenig

@Johannes: bin mit deinem Vorschlag a) einverstanden. b) entspricht einem Session-key Verwaltung, das waere fuer mich im Moment auch zu viel.

viegener

@Rudi: Schön, Patch ist anbei (mit Doku in allowed)
(wie oben vereinbart auch mit 80Z / FmtDateTimeRFC1123 etc)
In FHEMWeb ist nur der Teil enthalten um nach erfolgreichern Authenthifizierung den header zurückzugeben.

Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

rudolfkoenig


viegener

Zitat von: rudolfkoenig am 03 Januar 2016, 14:54:51
Habs ohne Aenderung eingecheckt.
Na das gibt mir doch gleich ein gutes Gefühl für den verbleibenden Sonntag  :)
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

rudolfkoenig

Wg. dem hier: http://forum.fhem.de/index.php/topic,46498.msg385840.html#msg385840 beschriebenen Problems moechte ich das Default beim nicht gesetzten validFor von "all" auf "none" setzen. Wenn jemand bessere Vorschlaege hat, bitte melden.

Markus Bloch

Wow Danke. Ich wollte gerade nachfragen, aber du warst schneller.

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

immi

Hi Rudolf
in fhem.pl is there a reason for the following  difference?
line 955
return "Forbidden command $cmd." if($cl && !Authorized($cl, "cmd", "perl"));

line 1015
return "Forbidden command $cmd." if($cl || !Authorized($cl,"cmd","shell"));

ciao
immi

rudolfkoenig

@immi: thanks for the note, I fixed it. It seems that people doing frequent FHEM-updates do not use shell commands.

Sonst: ich habe allowed wie angekuendigt umgebaut: ohne validFor ist allowed nicht gueltig.
Da es an diversen Ecken zu Problemen kommt, steht die Aenderung ab sofort fuer update zur Verfuegung.

immi