Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Xamarin - Shelly 1 Plus - Digest Authentifizierung
ChristophSharp
myCSharp.de - Member



Dabei seit:
Beiträge: 5

Themenstarter:

Xamarin - Shelly 1 Plus - Digest Authentifizierung

beantworten | zitieren | melden

Hallo liebe Leute,

Möchte in meiner Xamarin Forms App einen Shelly 1 Pro per Url ansprechen.
Seit der Pro Version wird eine Digest Authentifizierung benötigt ansonsten ist der Shelly ungeschützt.

Wenn ich die Authentifizierung ausschalte funktioniert der nachfolgende Code:


 private void LmuButton(object sender, EventArgs e)
             {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://192.168.10.68/relay/0?turn=on");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            }

Die Doko vom Shelly beinhaltet JavaScript Code die ich bisher leider nicht richtig in c# übersetzen kann.

https://shelly-api-docs.shelly.cloud/gen2/Overview/CommonDeviceTraits/#authentication

Hier Ausschnitte aus der Doku

Schritte im Prozess:

Der Client fordert eine geschützte Ressource an, ohne Anmeldeinformationen bereitzustellen.
Eine Serverantwort mit Fehler 401 (nicht autorisiert) wird empfangen.
Der Client fordert dieselbe geschützte Ressource an, gibt aber diesmal Anmeldeinformationen an.
Die Anforderung ist erfolgreich und der Zugriff auf die Ressource wird gewährt.
Bei der Kommunikation über HTTP muss dieser Vorgang für jede Anfrage wiederholt werden, die Sie an das Gerät senden. Für die Kommunikation über Websocket müssen die Schritte 1 und 2 jedoch nicht mehr als einmal durchlaufen werden: Sie müssen das authObjekt nur einmal erstellen (mehr dazu weiter unten ) und es dann für alle aufeinanderfolgenden Anforderungen an dieses Gerät verwenden.

Authentifizierung über
Bei der Kommunikation über einen HTTP-Kanal finden Sie diese Informationen im WWW-Authenticate- Header der Antwort.

Beispiel:

Anfrage
curl -X POST -i -d '{"id":1, "method":"Shelly.GetStatus"}' http://${SHELLY}/rpc
Antwort

HTTP/1.1 401 Unauthorized
Server: Mongoose/6.18
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Content-Length: 0
Connection: close
WWW-Authenticate: Digest qop="auth", realm="shellypro4pm-f008d1d8b8b8", nonce="60dc59c6", algorithm=SHA-256

Authentifizierung über
Bei der Kommunikation über einen Websocket-Kanal enthält die Antwort einen Fehlerrahmen, in dem die oben genannten Attribute zu finden sind.

Beispiel:

Anfrage
curl -X POST -d '{"id":1, "method":"Shelly.DetectLocation"}' http://${SHELLY}/rpc
Antwort
{
"id": 1,
"src": "shellypro4pm-f008d1d8b8b8",
"dst": "user_1",
"error": {
"code": 401,
"message": "{\"auth_type\": \"digest\", \"nonce\": 1625038762, \"nc\": 1, \"realm\": \"shellypro4pm-f008d1d8b8b8\", \"algorithm\": \"SHA-256\"}"
}
}
Erfolgreiche Anfrage mit
Damit die Anfrage richtig funktioniert, authsollte dem Anfragerahmen ein zusätzliches JSON-Objekt hinzugefügt werden. Es sollte enthalten:


realm: string, device_id des Shelly-Geräts. Erforderlich
username: string, muss auf admin gesetzt werden . Erforderlich
nonce: Zahl, Zufalls- oder Pseudo-Zufallszahl zur Verhinderung von Replay-Angriffen, entnommen aus der Fehlermeldung. Erforderlich
cnonce: Nummer, Client-Nonce, vom Client generierte Zufallszahl. Erforderlich
response: string, Kodierung des Strings <ha1> + ":" + <nonce> + ":" + <nc> + ":" + <cnonce> + ":" + "auth" + ":" + <ha2>in SHA256. Erforderlich
ha1: Zeichenfolge, <user>:<realm>:<password>codiert in SHA256
ha2: string, "dummy_method:dummy_uri" codiert in SHA256
algorithm: Zeichenkette, SHA-256 . Erforderlich

Beispiel:

Anfrage1

curl -X POST -d '{"id":1, "method":"Shelly.DetectLocation", "auth":
 {"realm": "shellypro4pm-f008d1d8b8b8", "username": "admin", "nonce": 1625038762,
 "cnonce": 313273957, "response": "eab75cbbd7acdb7082164cb52148cfbe351f28bf80856f93a23387c6157dbb69",
 "algorithm": "SHA-256"}}' \
  http://${SHELLY}/rpc

Oder:

Anfrage2
curl --digest -u admin:mypass http://${SHELLY}/rpc/Shelly.DetectLocation
Oder:

Anfrage3
curl --anyauth -u admin:mypass -X POST -d '{"id":1, "method":"Shelly.DetectLocation"}' http://${SHELLY}/rpc
Antwort

{
   "id": 1,
   "src": "shellypro4pm-f008d1d8b8b8",
   "dst": "user_1",
   "result": {
      "tz": "Europe/Sofia",
      "lat": 42.67236,
      "lon": 23.38738
   }
}


Ich hoffe mir kann einer weiterhelfen?

Viele Grüße
Christoph
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.826

beantworten | zitieren | melden

Was mir auf den ersten Blick auffällt, ohne Shelly zu kennen:

- Dein Request erfolgt ohne Verschlüsselung (kein HTTPS)
- Du hast keinerlei asynchronen Code. Synchroner Code, der blockiert und damit die App unbenutzbar macht, führt auf mobilen Plattformen jedoch dazu, dass die App zurecht abgeschossen wird
- Die Shelly Dokumentation zeigt kein Basic Auth, sondern Digest Auth

In .NET sollte man mit dem HttpClient arbeiten, nicht mit HttpWebRequest.
Der .NET HTTP Client nimmt dann auch die Arbeit bei einfachen Auth-Verfahren wie eben Basic und Digest ab.
Schritte:
- HttpClientHandler erzeugen, der ein Credential Objekt hält (hier wahrscheinlich NetworkCredential)
- Http Client erstellen und dabei den Handler übergeben
- Url aufrufen

Die .NET ist sehr sehr ausführlich was das Thema HttpClient und/oder Simple Credential Handling angeht, zB NetworkCredential Class (System.Net)
Man muss sie nur lesen ;-)
private Nachricht | Beiträge des Benutzers
ChristophSharp
myCSharp.de - Member



Dabei seit:
Beiträge: 5

Themenstarter:

beantworten | zitieren | melden

Hallo,
Abt vielen Dank für die Antwort.

Zu Punkt 1 . Verschlüsselung ist mit dem Shelly nicht möglich. Nur Http!

Habe noch einmal etwas zusammengebastelt.
Funktioniert auch wieder ohne Authentifizierung.
Mit der Authentifizierung kommt Fehlercode
System.Net.WebException: 'The remote server returned an error: (401) Unauthorized.'

Hier der Code


 private void LmuButton(object sender, EventArgs e)
        {

            var user = "admin";
            var password = "password";
            var url = "http://192.168.10.68/relay/0?turn=on";




            NetworkCredential myCred = new NetworkCredential(
            user, password);

            CredentialCache myCache = new CredentialCache();

            myCache.Add(new Uri(url), "Digest", myCred);
            

            WebRequest wr = WebRequest.Create(url);
            wr.Credentials = myCache;


            var client = new HttpClient();
            HttpWebResponse response = (HttpWebResponse)wr.GetResponse();


        }

Ja der Code ist noch asynchron.
Hat noch jemand einen Tipp?
Vielen Dank schon mal!

Viele Grüße
Christoph
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.826

beantworten | zitieren | melden

Und auf den HttpClientHandler hattest keine Lust? ;-)
private Nachricht | Beiträge des Benutzers
Papst
myCSharp.de - Experte



Dabei seit:
Beiträge: 421
Herkunft: Kassel

beantworten | zitieren | melden

Dein HttpClient macht nichts, du verwendest in deinem Code weiterhin den HttpWebRequest.
private Nachricht | Beiträge des Benutzers