Uploaded image for project: 'eZ Publish / Platform'
  1. eZ Publish / Platform
  2. EZP-30468

If user is logged in into two different SiteAccesses, an incorrect X-User-Hash gets cached and is used after logout.




      Steps to reproduce

      1. Set-up eZ Platform behind Varnish (use standard VCL: https://github.com/ezsystems/ezplatform-http-cache/blob/master/docs/varnish/vcl/varnish5.vcl).
      2. Configure different session cookie names for admin and frontend SA.
      3. Add the new controller, service, view and views configuration as explained below.
      4. Create an editor's account, for instance, John Doe.
      5. Create a new section, for instance, Restricted.
      6. Deny access for the anonymous group to the contents of Restricted section.
      7. Create a random folder in Standard section. Let's assume that it has LocationId: 100.
      8. Create a new random content object. Assign it to the Restricted section. Let's assume that it has ContentId: 102.
      9. Clear all browser cookies.
      10. Try to open the content created in step 7 using frontend SA as anonymous. You should not be able to see the content loaded via ESI.
      11. Login into the frontend SA as John Doe.
      12. Reload the page with restricted content. It should be visible now.
      13. Login into the backend SA as admin.
      14. Do some random clicks in AdminUI (go for Content, Media, whatever).
      15. Logout from the backend SA.
      16. Try to open the restricted page on the frontend. You shouldn't be able to view the content.

      Expected behavior
      You should be able to see restricted content due to the fact that your frontend SA session is still active.

      Technical reason for the issue

      1. When you open the page, as described in step 10, then the ESI call gets cached and vary on anonymous X-User-Hash. /_fos_user_context_hash call return anonymous hash, gets cached and vary on Cookie/Authorization (in this step there is no cookies).
      2. When you open the page, as described in step 12, the ESI call gets cached and vary on X-User-Hash (editor’s one). /_fos_user_context_hash call returns X-User-Hash for editor, gets cached and vary on Cookie/Authorization (there is a cookie for frontend SiteAccess session).
      3. When you login to the backend SA, as described in steps 13 & 14 then /_fos_user_context_hash call returns X-User-Hash for admin, gets cached and vary on Cookie/Authorization (there are two cookies now, one for the frontend SA and one for the backend SA)
      4. When you logout from the backend SA, as described in step 15, then there is a redirection to /admin/login, so a new “empty” session is created and the new backend SA cookie is set. Redirect causes next call for X-User-Hash. It returns anonymous hash (due to the “empty” backend cookie) and gets cached, vary on Cookie/Authorization. Therefore the anonymous X-User-Hash gets cached and vary on these two cookies:
        1. “empty” backend SA session cookie
        2. valid frontend SA session cookie

      Due to the last point, a response for the next ESI call for the frontend restricted page is considered as already existing in the cache since the request uses anonymous hash. There is no call for the X-User-Hash since there is already cached one for the mentioned set of cookies.

      Potential solutions

      1. Do not set the new, "empty" cookie after logout.
      2. Disable caching for X-User-Hash.
      3. Add some unique vary for X-User-Hash calls besides Cookie.

      Controller, view, views configuration for step 2:

      namespace AppBundle\Controller;
      use eZ\Bundle\EzPublishCoreBundle\Controller;
      use eZ\Publish\API\Repository\ContentService;
      use eZ\Publish\API\Repository\Exceptions\UnauthorizedException;
      use eZ\Publish\API\Repository\PermissionResolver;
      use Symfony\Component\HttpFoundation\Response;
      class BugController extends Controller
           * @var \eZ\Publish\API\Repository\PermissionResolver
          private $permissionResolver;
           * @var \eZ\Publish\API\Repository\ContentService
          private $contentService;
          public function __construct(PermissionResolver $permissionResolver, ContentService $contentService)
              $this->permissionResolver = $permissionResolver;
              $this->contentService = $contentService;
              $this->contentId = 102;
          public function contentAction(): Response
              $user = $this->permissionResolver->getCurrentUserReference();
              return $this->render(
                  ['user' => $user]
          public function esiContentAction(): Response
              $user = $this->permissionResolver->getCurrentUserReference();
              try {
                  $content = $this->contentService->loadContent($this->contentId);
                  $content = $content->contentInfo->name . ', UserID: ' . $user->getUserId();
              } catch (UnauthorizedException $e) {
                  $content = 'Unauthorized, UserID: '. $user->getUserId();
              $response = new Response($content);
              return $response;
      <h3>UserID: {{ user.userId }}</h3>
      {{ render_esi(controller('AppBundle:Bug:esiContent')) }}
          AppBundle\Controller\BugController: ~
                      name: admin_session
                  languages: [eng-GB]
                      name: site_session
                              controller: AppBundle:Bug:content
                                  Id\Location: 100




            kamil.madejski@ez.no Kamil Madejski
            3 Vote for this issue
            5 Start watching this issue