View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0007978 | OXID eShop (all versions) | 1.05. Users | public | 2026-07-16 13:55 | 2026-07-16 13:55 |
| Reporter | rene.gust | Assigned To | |||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | new | Resolution | open | ||
| Product Version | 7.4.1 | ||||
| Summary | 0007978: login token for admin and frontend user | ||||
| Description | - In our project we have an impersonation feature that lets an admin user load a frontend user and place orders on their behalf. This worked fine up to OXID 7.0. - OXID 7.4 introduced a login-token mechanism (in UserComponent and in User::loadActiveUser()): on login a hash derived from the user's password hash is stored in the session under a single key login-token, and on every loadActiveUser() call it is re-verified against the current password hash — if it doesn't match, the user is logged out. - This breaks impersonation, because the core uses one shared login-token key for both the admin (backend) and the frontend user, distinguished only at runtime via isAdmin(). With admin and frontend logged in in parallel within the same session, whichever context writes the token last overwrites the other, so the other context fails the check and gets logged out. - I've worked out a workaround that splits the token into two context-specific session slots (login-token-admin / login-token-frontend) and translates between them and the generic login-token key the core expects, leaving the actual verifyHash check untouched. - My concern: this relies on the internal login-token key name and the way the core reads/writes it. If a future OXID version renames the key, changes where it's set, or alters the verification flow, the workaround will silently break. - Question: is the login-token handling considered stable/public API, or is it an internal implementation detail that may change? And is there an officially supported extension point for impersonation-style parallel sessions that I should use instead? Thanks | ||||
| Additional Information | <?php namespace OxidProfessionalServices\Impersonation\Model; use OxidEsales\Eshop\Core\Registry; class UserLoginToken extends User_parent { private const LOGIN_TOKEN_CORE = 'login-token'; private const LOGIN_TOKEN_ADMIN = 'login-token-admin'; private const LOGIN_TOKEN_FRONTEND = 'login-token-frontend'; public function login($userName, $password, $setSessionCookie = false) { $result = parent::login($userName, $password, $setSessionCookie); // parent stored 'login-token' in the current isAdmin() context. // Mirror it into the context-specific slot and drop the generic one, // so admin and frontend impersonation don't overwrite each other. $session = Registry::getSession(); $token = $session->getVariable(self::LOGIN_TOKEN_CORE); if ($token !== null) { $session->setVariable($this->getLoginTokenName(), $token); $session->deleteVariable(self::LOGIN_TOKEN_CORE); } return $result; } public function loadActiveUser($blForceAdmin = false) { // Restore the context-specific token into the generic slot before the // parent call, so parent::loadActiveUser() finds it as usual. // Note: the same admin context as in the parent applies here, incl. $blForceAdmin. $session = Registry::getSession(); $token = $session->getVariable($this->getLoginTokenName($blForceAdmin)); if ($token !== null) { $session->setVariable(self::LOGIN_TOKEN_CORE, $token); } $result = parent::loadActiveUser($blForceAdmin); // Clean up: don't leave the generic slot lying around persistently. $session->deleteVariable(self::LOGIN_TOKEN_CORE); return $result; } public function logout() { $result = parent::logout(); // parent only deletes 'login-token'. Remove just the slot of the current // context, so a frontend logout doesn't tear down a parallel admin session // (and vice versa). Registry::getSession()->deleteVariable($this->getLoginTokenName()); return $result; } private function getLoginTokenName(bool $forceAdmin = false): string { return ($this->isAdmin() || $forceAdmin) ? self::LOGIN_TOKEN_ADMIN : self::LOGIN_TOKEN_FRONTEND; } } | ||||
| Tags | No tags attached. | ||||
| Theme | Not defined | ||||
| Browser | Not defined | ||||
| PHP Version | Not defined | ||||
| Database Version | Not defined | ||||