Záhada s přihlášením jiného uživatele, přepsání identity, UserPanel
- elendir
- Člen | 31
Omlouvám se za bulvární titulek – chyba je nejspíš mezi židlí a klávesnicí. Pro přihlašování používám téměř čisté Nette 2.0.6 s tradičním Authenticatorem. Když jsem zalogován jako uživatel Jedna a přes Sign:in se pokusím zalogovat jako uživatel Dva (bez toho abych se předtím odlogoval), Nette se tváří že ok, ale po následném přesměrování přihlášen nejsem a jsem vrácen na Sign:in. Hned za
$this->getUser()->login($values->username, $values->password);
jsem si tedy vydumpoval identitu (správně již obsahuje uživatele Dva) a $_SESSION – ta ale pod klíčem
["Nette.Http.UserStorage/"]["identity"]
obsahuje stále identitu uživatele Jedna, o identitě uživatele Dva není v celé $_SESSION ani zmínka. Tento problém se objevil při přechodu na 2.0.6 (bohužel už nevím odkud, možná 2.0.3) a projevil se mimo jiné tím, že mi náhle přestal fungovat UserPanel. Debugoval jsem X hodin a ani ťuk. Nemohl byste to prosím někdo s 2.0.6 jen v rychlosti zkusit reprodukovat v nějaké svojí aplikaci, případně mě zkusit nasměrovat? Díky moc!
Editoval elendir (23. 10. 2012 17:22)
- elendir
- Člen | 31
Tak a aby toho nebylo málo, dumpnul jsem pro jistotu i
$this->getUser()->getStorage()
a její private proměnná sessionSection obsahuje pod klíčem
["Nette.Http.UserStorage/"]["identity"]
správně identitu uživatele Dva. Jak je možné že SessionSection obsahuje data, která nejsou v $_SESSION? Připadám si trošinku jako idiot. :-)
Editoval elendir (23. 10. 2012 17:21)
- elendir
- Člen | 31
Děkuju za reakci, matně si vzpomínám že to jsem zkoušel už odpoledne a mám dojem že to pomohlo. Nepamatuju si to ale jistě, protože fungujících workaroundů jsem našel víc. Ale prostý workaround jsem zavrhnul. Bál jsem se že jde o hlubší problém který by mi, při jeho nepochopení, mohl rozhodit zabezpečení celé aplikace. V tomto okamžiku mám podezření, že se jedná o bug – konkrétně že by zde ve třídě Session namísto
$backup = $_SESSION;
session_start();
$_SESSION = $backup;
mělo být spíš něco jako
$backup = & $_SESSION;
session_start();
$_SESSION = & $backup;
jelikož SessionSection má do pole $_SESSION nastavené 2 reference přes které do něj vkládá data, ale zkopírováním do proměnné $backup o ně přijde. Nevím, zatím nerozumím tomu proč tam je zrovna tenhle kus kódu. Je už pozdě takže nebudu radši vynášet předčasné soudy a zítra to prověřím.
Editoval elendir (23. 10. 2012 22:10)
- elendir
- Člen | 31
Tak jsem se díval na tu metodu logout a obávám se že její explicitní volání nepomůže, poněvadž hned první řádek ve fci User::login() je
$this->logout(TRUE);
Popíšu zde podrobněji co jsem objevil, kritické části kódu jsou podle mně: metoda start v SessionSection, kde dojde k „napojení“ dvou parametrů třídy do pole $_SESSION by-reference:
$this->data = & $_SESSION['__NF']['DATA'][$this->name];
$this->meta = & $_SESSION['__NF']['META'][$this->name];
a následně metoda regenerateId ve třídě Session kde dojde ke zkopírování pole $_SESSION, což jestli se nepletu rozbije tyto reference, respektive tyto reference poté vedou do neaktuálního pole $_SESSION.
Proces při zavolání User::login() je následující:
- User::logout() odhlašuje aktuálně přihlášeného, to vede k volání Session::regenerateId() a dochází k tomu, že od tohoto okamžiku již výše uvedené reference odkazují do neaktuálního $_SESSION pole a všechna data zápsaná do session prostřednictvím třídy SessionSection od tohoto momentu dál budou tím pádem ztracena.
- User::login() se provede v pořádku ale identita se zapíše do neaktuálního $_SESSION pole.
- Po úspěšném přihlášení dochází k přesměrování ale nová identita není v $_SESSION, byla totiž uložena jinam.
Je sice fakt pozdě takže jsem možná úplně mimo a možná je to celé blbost, ale strávil jsem nad tím 15 hodin, velmi prosím nějakého zkušeného nettistu jestli by se na to mohl mrknout a ověřit to. Nebude-li mé zoufalé volání vyslyšeno zde, šoupnu to do hlášení chyb.
Editoval elendir (23. 10. 2012 23:39)
- elendir
- Člen | 31
Ještě bych chtěl dodat, že zde pozoruji určitou souvislost s tímto poměrně ujetým problémem, který popisoval @mcmatak. Ale teď už jdu fakt spát.
- elendir
- Člen | 31
Tak abych to uzavřel: hodil jsem to do issues na Githubu. Opravit se mi to nepodařilo a nejsem schopen tomu v této chvíli věnovat více času. Byl jsem proto nucen zakomentovat problematické řádky v Nette\Http\Session::regenerateId(). Vzhledem k tomu, že se jedná o základ práce se session na kterém je závislá hromada věcí, těžko říct co všechno tím může být ještě ovlivněné. Doporučoval bych proto, aby to někdo (šikovnější než já) opravil.
- David Grudl
- Nette Core | 8222
Bylo by dobré zkusit smazat cookies (nebo zkusit to v jiném prohlížeči) a jestli to nebude fungovat ani tam, tak zjisti, ve které verzi Nette se chyba objevila. Máš nějakou opcode cache?
- elendir
- Člen | 31
Potvrzuji že problém přetrvává po vymazání cookies a je nezávislý na prohlížeči (testováno Chrome, Opera, FF). Po zakomentování těchto řádek ve fci regenerateId
session_regenerate_id(TRUE);
session_write_close();
$backup = $_SESSION;
session_start();
$_SESSION = $backup;
je problém odstraněn. Původně (ještě před tím než jsem to zbaběle zakomentoval) jsem se tam pokusil udržet ty 2 výše popisované reference pomocí
$backup = & $_SESSION;
session_start();
$_SESSION = & $backup;
ale to nepomohlo. Tipnul bych si že session_start() to pole $_SESSION vyNULLuje nebo s ním prostě provede nějakou operaci která breakne ty 2 reference vedoucí dovnitř $_SESSION[‚__NF‘][‚DATA‘], ale to je fakt jen nápad, neměl jsem bohužel čas to ověřit.
EDIT: Jo a ve které verzi se chyba objevila bohužel také nevím, ale s největší pravděpodobností v okamžiku kdy se objevil ten výše uvedný blok kódu, což bylo podle Githubu nějak cca před 7 měsíci jestli si dobře vzpomínám. Moje původní verze nette byla určitě stará alespoň rok, tzn tento kód neobsahovala a popisovaný problém neexistoval.
EDIT2: Ještě bych chtěl zdůraznit hlavní vodítko – problém se projevuje pouze když se pokusím zalogovat jako uživatel DVA v okamžiku kdy jsem zalogován jako uživatel JEDNA. V případě, že se nejprve pomocí Sign:out odloguju, jsem přesměrován na Sign:in a zaloguji se jako užiovatel DVA, proběhne vše v pořádku.
EDIT3: Opcode cache nemám. I nette cache promazávám. Tohle už je snad poslední edit, sorry. :-)
Editoval elendir (25. 10. 2012 11:36)
- David Grudl
- Nette Core | 8222
Pod jakou verzí PHP se tak děje?
session_start() skutečně pole $_SESSION zruší a znovuvytvoří, právě proto je tam použitá proměnná $backup. Takže reference se nebreaknou a stále vedou do pole $_SESSION.
- elendir
- Člen | 31
David Grudl napsal(a):
session_start() skutečně pole $_SESSION zruší a znovuvytvoří, právě proto je tam použitá proměnná $backup. Takže reference se nebreaknou a stále vedou do pole $_SESSION.
Špatně jsem se vyjádřil, měl jsem na mysli alternativu, kdy session_start() provede něco přímo s obsahem $_SESSION, tj. že si sáhne na ty reference a nějak pokazí přímo tu hodnotu na kterou tyto reference směřují (čímž pokazí i $backup). Taky to může dělat už ta fce session_write_close(). Fakt mě mrzí že jsem neměl víc času to dohledat, sorry.
EDIT: Možná že plácám blbosti, už jsem to půl roku neviděl.
EDIT2: Jasně, plácám blbosti, zapomněl jsem že ta reference směřuje do
$_SESSION a nikoliv ze $_SESSION ven, takže tenhle post prosím ignoruj.
Editoval elendir (16. 4. 2013 16:39)
- Pavel S.
- Člen | 24
Zdá se mi, že mám hodně podobný problém jako elendir. Zakomentovat zmíněných 5 řádků v Session pomůže. Zkusím popsat podrobnosti:
Mám přihlášeného uživatele s user name ‚guest123‘, je to anonymní uživatel (ale přihlášený). Ten vyplní své uživatelské údaje a chci ho přehlásit jako ‚jarda.vomacka‘:
$this->user->login('jarda.vomacka', 'jardovoheslo');
Přihlášení proběhne v pořádku a v identitě se aktualizují údaje
o novém uživateli. Kontrolní $this->user->isLoggedIn()
vrací true. Jakmile ale udělám refresh, resp. přechod na další stránku
v aplikaci, na serveru vidím dva problémy:
$this->user->isLoggedIn()
vrací false$this->user->identity
neobsahuje data o novém uživateli (před refreshem obsahovala)
Pokud by to mělo mít vliv, pro úplnost dodávám, že moje aplikace
používá iframes. Ačkoli i když jsem je eliminoval, tak problém stále
přetrvává. Pomůže zakomentovat 6 řádků v Session, jak je popsáno
tady:
https://forum.nette.org/…ty-userpanel#…
- David Grudl
- Nette Core | 8222
Mohl by jsi mi poslat emailem nějaké torzo aplikace, kde se to projevuje, s postupem, jak chyby docilit?
- elendir
- Člen | 31
Ano, Pavel S. popisuje identický problém. Pokusil jsem se reprodukovat tu chybu na aktuálním nette sandboxu. Na lokále (XAMPP) funguje bez problému. Když ale překopíruju aplikaci na firemní server tak to začne blbnout. To je asi ta nejhorší varianta, protože chyba tedy nejspíš není v aplikaci či v nette, ale možná v nastavení serveru, verzi PHP apod. Jestli chceš, můžu ti poslat ten sandbox a phphinfo, já už nějak nemám motivaci to dál analyzovat když to blbne jen dvěma lidem z celé komunity (evidentně těm, kteří si nejsou schopní ani správně nastavit server) :-)
- saimons
- Člen | 293
Ja mam osobne take nake zahadne problemy s prihlasovanim uzivatelu na serveru. Pouzivam verzi 2.0.10 a prihlasovani je skoro totozne se sandboxem. Jedine co tam mam jinak je, ze vsechny uzivatele prihlasuji trvale s expiraci 14 dnu. Cas od casu mi prijde email od nakeho uzivatele, ze jim nefunguje prihlaseni, ale pouze v jednom prohlizeci. Vzdalene jsme kontrolovali nastaveni jeho prohlizece a vse se zdalo v poradku. Bohuzel se nam chyba nepodarila nasimulovat na zadnem z nasich PC. Pokusim se jeste dododat vice informaci, protoze mi je jasne, ze jsem k vyreseni moc neprispel.