Cookies übergeben

Hi,
ich versuche mich gerade daran, dass Unifi Modul so zu erstellen, dass es etwas einfacher wird … also z.B. nicht alles Variablen angelegt werden oder andere Dinge Möglich sind. Die API von denen ist jetzt nicht so kompliziert.

Was ich aber ums verr… nicht hinbekomme, ist das Login (welches funktioniert) dann für einen weiteren Aufruf zu verwenden. Ich versuche jetzt schon seit Stunden den Code im alten Modul, welche ja von „the art of wlan“ kommt anzupassen - aber das Login Thema killt mich.

Evtl. kann mir jemand einen Tipp geben.


$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://192.168.1.1/api/auth/login');
curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/32.0.1700.107 Chrome/32.0.1700.107 Safari/537.36');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS, "username=".$User."&password=".$Password);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, "/tmp/unifi_cookie");
    curl_setopt($ch, CURLOPT_COOKIEJAR, "/tmp/unifi_cookie");
curl_setopt($ch, CURLOPT_COOKIEJAR, "unifi_cookie");
$answer1 = curl_exec($ch);
if (curl_error($ch)) {
    echo curl_error($ch);
}
var_dump ($answer1);

curl_close ($ch);
unset($ch);

//another request preserving the session
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://192.168.1.1/proxy/network/api/s/default/stat/health');
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_COOKIEFILE, "/tmp/unifi_cookie");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
//curl_setopt($ch, CURLOPT_POSTFIELDS, "");
$answer = curl_exec($ch);
if (curl_error($ch)) {
    echo curl_error($ch);
}
var_dump ($answer);

Ich habe jetzt noch ein wenig gegoogelt und von @ubittner den Verweis auf Nello gefunden.

Ich kann jetzt das Cookie - also eine sehr lange ID extrahieren, aber wie bekommt man dieses Cookies (also die ID wieder in den folgenden Curl Aufruf)?

curl_setopt($ch, CURLOPT_COOKIE, $cookies);

funktioniert leider nicht.

Ist hier vielleicht etwas dabei?

Leider finde ich bei mir den „alten“ Code nichtmehr.

Uli

Danke - leider nein … den Code hatte ich dann gefunden und ich konnte das Cookie extrahieren (also ja - hat geholfen) :smiley: . Das doofe ist, das ich keinen Plan habe wie ich den Inhalt des Cookies wieder in meinen curl Aufruf bekomme.

Das habe ich noch gefunden:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile); // Cookie aware
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile); // Cookie aware
$content = curl_exec($ch);
curl_close($ch);

wobei:

$cookieFile = "cookies.txt";
if(!file_exists($cookieFile)) {
    $fh = fopen($cookieFile, "w");
    fwrite($fh, "");
    fclose($fh);
}

Oder den Inhalt über den Buffer auslesen, wenn du es als file nicht gespeichert hast.

To do a PHP CURL call with cookies, we use CURLOPT_COOKIEJAR to specify where to save the cookie after the call ends, and CURLOPT_COOKIEFILE to specify which cookie file to send to the remote server.

Uli

Leider funktionieren die die Cookie file und jar nicht wirklich in Symcon, da ein Modul oder auch sonst nichts ins Dateisystem schreiben darf?

Ich habe den Cookie Inhalt - ist eine ewig lange Nummer, wobei ich nicht weis wie ich den Inhalt sinnvoll wieder an der nächste Modul gebe - hierbei ist der Wert auch nicht das Thema, weil ich in einem Script bin - im modul nutze ich dann set_buffer.

Ich muss morgen nochmal probieren. Das muss doch gehen.

Nie getestet, aber hier steht du kannst den Cookie auch selber im Header setzen, ohne eine Datei zu benutzen (mit Beispiel)

Oder die curl Option CURLOPT_COOKIE benutzen und dort deinen Cookie (als String) platzieren.
Michael

Moin,
danke Michael … das habe ich auch mal probiert … geht leider auch nicht. Ich muss mal weiter suchen und basteln.

Also das ist der Code mit dem ich ein Cookie bekomme:

"TOKEN=eyJhbGciOiJIUzI1NiIsInR … " - kommt sauber bei var_dump($cookies) … unten versuche ich es wieder aufzugreifen und das scheint nicht zu gehen.

Ich versuche das Cookie sogar 2 x zu setzen (Header und Cookie Option).

Was komisch ist, ist der Umstand, dass seit ich den Header auslese und via Verbose ausgebe, seht im header 404 … aber ich weis, dass die Seit funktioniert? Das ist alles sehr komisch. Den Code im Unifi Reloaded Modul verstehe ich nicht wirklich - klar funktioniert er, aber so richtig wartbar ist der m.E. nicht - weswegen ich gerne eine Vereinfachung anstreben würde.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://192.168.1.1/');
curl_setopt($ch, CURLOPT_POSTFIELDS, "username=".$User."&password=".$Password);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 

$data = curl_exec($ch);
curl_close($ch);v

preg_match_all('|Set-Cookie: (.*);|U', $data, $matches);   
$cookies = implode('; ', $matches[1]);

var_dump ($cookies);

$debug = true;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://192.168.1.1/proxy/network/api/s/default/stat/health');
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array($cookies));
//curl_setopt($ch, CURLOPT_SSLVERSION, 3); //YOU CAN DELETE THIS
curl_setopt($ch, CURLOPT_SSLVERSION, 'CURL_SSLVERSION_TLSv1'); //ADD THIS	   
curl_setopt($ch , CURLOPT_RETURNTRANSFER, true);
if ($debug == true) {
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);    
}
if ($cookies != "") {
curl_setopt($ch, CURLOPT_COOKIE,  $cookies);
echo "cookie set";
}
//return $ch;
$data = curl_exec($ch);
var_dump($data);

Fehlt im ersten Aufruf.
Und sind die Postdata korrekt kodiert?
CURLOPT_POSTFIELDS akzeptiert auch ein Array mit Key/Value und macht das dann selber korrekt.

Beim zweiten Aufruf hast du dagegen CURLOPT_POST gesetzt, aber keine Post-Daten.

Ist falsch, weil du jetzt ja nur den Cookie-String ohne den Namen vom Feld im Header setzt.
Der Inhalt sollte so sein:
array("Cookie: ".$cookies)
Du kannst die auch die gesendeten und empfangenen Header ausgeben lassen. Da sieht man häufig dann die Ursache.

Michael

Also der erste Teil stimmt mit dem Login … ich bekomme ja meine Cookie ID.

Im zweiten Teil habe ich setopt entfernt und ich glaube jetzt kommt das Cookie mit …

X-Response-Time: 3ms
Set-Cookie: TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjc3JmVG9rZW4iOiJiMmM3ZTYxNi1lNDQ5LTQxMWQtOTY2MC0zOTJkOTNmNTJmMDMiLCJpYXQiOjE2Mjg0MTI2NTMsImV4cCI6MTYyODQxNjI1M30.P3o3CzsjedA4Gq-_CKSIk09Xnq_Fxn4IRfKxWQsbZbA; path=/; samesite=strict; secure; httponly
Content-Type: text/plain; charset=utf-8

Das blöde ist nur, dass ich immer noch ein unauthorized bekomme.

Die URL stimmt aber wenn ich sie mit dem Browser aufrufe.

Was ich auch nicht verstehe ist, dass das Unifi Modul anscheinend seine Cookies in eine Datei schreibt … kann ein Modul das und nur ein script kann es nicht? Evtl. versuche ich hier ein Problem zu lösen, dass es nicht gibt ???

Generell ist es mir unklar wie die Aufrufe im Modul in Bezug auch eine Session laufen.

Es scheinst das

  1. die Klasse Login aufgerufen wird (die holt sich ein Cookie und setzt die Session auf
  2. die Klasse xyz wird aufgerufen die etwas machen soll

Haben hier Module andere Voraussetzungen als ein Script mit dem ich teste?
// Anmerkung … habe mal ein Modul gebaut … geht genauso wenig

Du hattest 404 geschrieben und das ist not found und nicht unauthorized.
Zumal der Code jedes Mal anders aussieht und du nicht einmal die Header komplett zeigst ist das viel raten.
Der Cookie schaut auch so aus, als wenn da mehr als nur der token enthalten ist. Nicht das z.B. die path=/ oder httponly verändert oder nicht übertragen werden darf. Aber das sind nur Mutmaßungen.

Zum Thema Modul:
Nur für einen doofen Cookie würde ich keinen Aufwand für Zugriffe und Aufräumen auf dem Dateisystem betreiben.
Zumal einige SD Karten auf den Pi benutzen oder andere Windows mit anderen Pfaden.
Den String einfach in einen Buffer oder besser in ein Attribut schreiben und fertig.

Michael
PS: hat das Echoremote Modul nicht auch Cookies benutzt?

Also der komplette Code aktuell ist

$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_URL, $URL.'/api/auth/login');
curl_setopt($ch, CURLOPT_POSTFIELDS, "username=".$User."&password=".$Password);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 

$data = curl_exec($ch);

/*
preg_match_all('|Set-Cookie: (.*);|U', $data, $matches);   
$cookies = implode('; ', $matches[1]);
*/

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$body        = trim(substr($data, $header_size));
$code        = curl_getinfo($ch, CURLINFO_HTTP_CODE);

preg_match_all('|Set-Cookie: (.*);|U', substr($data, 0, $header_size), $results);
if (isset($results[1])) {
    $cookies = implode(';', $results[1]);
    if (!empty($body)) {
        if (($code >= 200) && ($code < 400)) {
            
                echo "logged in\n";
            
        }

        if ($code === 400) {
                echo 'We have received an HTTP response status: 400. Probably a controller login failure';
                return $code;
        }
    }
}

var_dump ($cookies);

$debug = true;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $URL.'/proxy/network/api/s/default/self');
//curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_HTTPGET, TRUE);
curl_setopt($ch , CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array($cookies));
curl_setopt($ch, CURLOPT_SSLVERSION, 3); //YOU CAN DELETE THIS
curl_setopt($ch, CURLOPT_SSLVERSION, 'CURL_SSLVERSION_TLSv1'); //ADD THIS	   
//if ($debug == true) {
//curl_setopt($ch, CURLOPT_VERBOSE, TRUE);    
//}
/*
if ($cookies != "") {
curl_setopt($ch, CURLOPT_COOKIE,  $cookies);
echo "cookie set";
}
*/
//return $ch;
$data = curl_exec($ch);
var_dump($data);

Der Header bez. Auszug der Mledungen schaut wie folgt aus:

logged in
string(266) "TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjc3JmVG9rZW4iOiI3OWNkZGMxNy01OWM5LTQ0NjgtODNiMy1lODA4YWUxOTNhMjEiLCJ1c2VySWQiOiIxZmFjNmNmYi01MmViLTRhMjgtODhlNC02ZTNmMzdhZjAwMjMiLCJpYXQiOjE2Mjg0MTcyOTksImV4cCI6MTYyODQyMDg5OX0.XkLncYzmyZB65GCwexN-OfFhrDw5Ckio73Bke-RwTCk"
string(771) "HTTP/1.1 401 Unauthorized
Vary: Origin
X-DNS-Prefetch-Control: off
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Download-Options: noopen
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Accept-Ranges: bytes
X-CSRF-Token: e980005c-0645-4f59-b1f2-52626854ca3e
X-Response-Time: 2ms
Set-Cookie: TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjc3JmVG9rZW4iOiJlOTgwMDA1Yy0wNjQ1LTRmNTktYjFmMi01MjYyNjg1NGNhM2UiLCJpYXQiOjE2Mjg0MTcyOTksImV4cCI6MTYyODQyMDg5OX0.CuYAi7gZTgtnG9E8b5l9aeRygNDOzL7u7b6ZxvxG1m0; path=/; samesite=strict; secure; httponly
Content-Type: text/plain; charset=utf-8
Content-Length: 12
Date: Sun, 08 Aug 2021 10:08:19 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Unauthorized"

Ich würde wirklich gerne ohne Datei arbeiten - gerade auch wegen Windows vs. Linux usw.

Noch immer falsch.
Steht in meinem Beitrag und auf stackoverflow wie es geht.
Die gesendeten Header wären wichtig. Damit man sieht was falsch rausgeht.
Michael

Das mich dem Cookie habe ich korrigiert.

curl_setopt($ch, CURLOPT_HTTPHEADER, array("Cookies: ".$cookies));

das scheint auch passend gesetzt zu werden

X-Response-Time: 3ms
Set-Cookie: TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjc3JmVG9rZW4iOiJkZjAyMjg1MC1iMTk3LTQ1OWMtODBhMC01YTc1Zjg0MGMyYTMiLCJpYXQiOjE2Mjg0MTkxMzIsImV4cCI6MTYyODQyMjczMn0.9M66NvMl_2DPWYSwM3E_dPkij4W9TDFe9Zoy6VlAHGw; path=/; samesite=strict; secure; httponly
Content-Type: text/plain; charset=utf-8

Wenn ich mir den Header via curl_getinfo ausgeben lasse, also oben dann kommt das hier - leider ohne verweis auf Cookies oder wie die referenziert werden.

array(37) {
  ["url"]=>
  string(38) "https://192.168.1.1:443/api/auth/login"
  ["content_type"]=>
  string(31) "application/json; charset=utf-8"
  ["http_code"]=>
  int(200)
  ["header_size"]=>
  int(823)
  ["request_size"]=>
  int(181)
  ["filetime"]=>
  int(-1)
  ["ssl_verify_result"]=>
  int(18)
  ["redirect_count"]=>
  int(0)
  ["total_time"]=>
  float(0.258385)
  ["namelookup_time"]=>
  float(0.000176)
  ["connect_time"]=>
  float(0.00076)
  ["pretransfer_time"]=>
  float(0.09585)
  ["size_upload"]=>
  float(47)
  ["size_download"]=>
  float(1184)
  ["speed_download"]=>
  float(4589)
  ["speed_upload"]=>
  float(182)
  ["download_content_length"]=>
  float(1184)
  ["upload_content_length"]=>
  float(47)
  ["starttransfer_time"]=>
  float(0.258229)
  ["redirect_time"]=>
  float(0)
  ["redirect_url"]=>
  string(0) ""
  ["primary_ip"]=>
  string(11) "192.168.1.1"
  ["certinfo"]=>
  array(0) {
  }
  ["primary_port"]=>
  int(443)
  ["local_ip"]=>
  string(12) "192.168.1.11"
  ["local_port"]=>
  int(35420)
  ["http_version"]=>
  int(2)
  ["protocol"]=>
  int(2)
  ["ssl_verifyresult"]=>
  int(0)
  ["scheme"]=>
  string(5) "HTTPS"
  ["appconnect_time_us"]=>
  int(95660)
  ["connect_time_us"]=>
  int(760)
  ["namelookup_time_us"]=>
  int(176)
  ["pretransfer_time_us"]=>
  int(95850)
  ["redirect_time_us"]=>
  int(0)
  ["starttransfer_time_us"]=>
  int(258229)
  ["total_time_us"]=>
  int(258385)
}

ICH HABS … yippi und danke Michael

curl_setopt($ch, CURLOPT_HTTPHEADER, array("cookie: ".$cookies));

cookies musste klein geschrieben sein und ohne „s“ - ja - es hat auch im Ursprung gefehlt.

Mal gucken was ich die nächsten Wochen hinbekomme.

1 „Gefällt mir“

Ich bin an sich jetzt großer Held beim übergeben von Cookies, aber habe eine neue Herausforderung … Cookie und JSON übergeben im Header

Mein JSON sieht wie folgt aus:

$CommandToController = array('cmd' => $Command, 'mac' => strtolower($DeviceMacAdress));

Mein Cookie

TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjc3JmVG9rZW4iOiI4ZjgzM2M0NS0xOGE5LTQwMGEtOTYxZC1hNzRlOGM2MDg3YmEiLCJ1c2VySWQiOiIxZmFjNmNmYi01MmViLTRhMjgtODhlNC02ZTNmMzdhZjAwMjMiLCJpYXQiOjE2Mjg3NzY2ODUsImV4cCI6MTYyODc4MDI4NX0.RXo4zmTnl5HCSPye9r19aAST-eOHz7uyRd33VMHRJzE

Mein CURL Aufruf

$ch = curl_init();
				if ($ControllerType == 0) {
					$MiddlePartURL = "/proxy/network/";
				}
				elseif ($ControllerType == 1) {
					$MiddlePartURL = "/";
				}	
				curl_setopt($ch, CURLOPT_POST, 1);
				
				curl_setopt($ch, CURLOPT_HTTPHEADER, array("cookie: ".$Cookie));
				//curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
				
				curl_setopt($ch, CURLOPT_URL, "https://192.168.1.1/proxy/network/api/s/default/cmd/stamgr");
				curl_setopt($ch, CURLOPT_POSTFIELDS, $CommandToController);
				curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
				curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);	
				curl_setopt($ch, CURLOPT_SSLVERSION, 'CURL_SSLVERSION_TLSv1');
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
					    

				$RawData = curl_exec($ch);
				$this->SendDebug($this->Translate("Device Blocker"),$this->Translate("Feedback from UniFi Controller ").$RawData,0);

Wenn ich

//curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));

Nicht verwende funktioniert die Anmeldung mit dem Cookie - aber das JSON wird anscheinend nicht codiert.

Wenn ich obiges einschalte bei er vermutlich mein JSON ein, aber das Cookie wird nicht mehr verwendet, da vermutlich der Header jetzt alles in JSON umsetzt.

Leider kenne ich mich mit den Cookies nur bedingt aus und somit stellt sich die Frage wie ich ein Cookie in ein JSON umsetze oder ob es sonst einen guten Weg gibt?

Ich sehe da kein json.
Du hast ein Array welche du mit CURLOPT_POSTFIELDS übergibst. Das sind dann Daten von einen Formular in dem entsprechenden Format:

Michael

ich hatte vorher

$CommandToController = json_encode(array('cmd' => $Command, 'mac' => strtolower($DeviceMacAdress)));

im Einsatz …

Ich bin aber nicht sicher wer da gerade zickt, da sich Unifi Controller je nach Variante sehr merkwürdig verhalten. Deswegen auch mein Versuch mal alles in JSON umzuziehen.