Problem/Motivation
I'm currently working on swapping out 404/403 pages from using nodes to a static HTML response for performance reasons. While doing this one of our tests started to fail that hit a taxonomy term page as an anonymous user, ensured that the response was a 404, then hit it as an admin and ensured it was a 200. The code this was testing was a hook_entity_access hook which denied access to view terms of specific vocabularies based on a permission.
The problem that I'm seeing is that the initial 404 is cached in dynamic_page_cache and has no cache contexts around user permissions even though the cache headers report there should be a user.permissions cache context on the response.
The taxonomy term page is delivered via a view with the "Content: Has taxonomy term ID" contextual filter. The contextual filter has the "Validate user has access to the Taxonomy term" option checked so when a user visits a term page, the view will then check the user has view access to that term, triggering our access hook.
This coincidentally worked fine without static 404 handling because we were using core's settings to serve a node page, therefore the cache contexts were added to the response from that node route which include the user.permissions context.
However, that doesn't seem to be done with this Views page because \Drupal\views\Plugin\views\argument_validator\Entity::validateEntity just returns FALSE based on $entity->access() and doesn't bubble up any cacheable metadata.
The codepath then sets $this->view->build_info['fail'] to TRUE and Drupal\views\Plugin\views\display\PathPluginBase::execute throws a NotFoundHttpException
I can explicitly add user.permissions to my response from my custom static 404 handler to fix it, but I don't have this same issue with any other types of pages, only these views pages set up with this particular access flow.
Proposed resolution
Somehow bubble up the cacheable data?
Issue fork drupal-3091671
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #9
danflanagan8I ran into a similar situation recently. It can technically result in information disclosure, but the security team decided this is an issue we can handle in public. Here's how I reported the issue to security (issue 180326):
Comment #10
danflanagan8On that security issue, @lendude had some nice comments that I want to put here:
I replied with:
Comment #11
danflanagan8Aha! There is a way to get runtime cacheability for argument-related plugins! I knew I had done something that worked before. That was in the contrib space for #3240332: Cache tags not added to View. Luckily, my patch has a great comment that leads us to the core issue: #2853592: Cacheability metadata can't be set from within argument default handlers.
That technique seems really weird, but it could be used in the absence of a better api.
Comment #13
danflanagan8I added a fail test that exposes the bug. Now we just need to fix it!
Comment #14
danflanagan8I pushed up a fix that uses the same kind of funky technique as #2853592: Cacheability metadata can't be set from within argument default handlers..
Comment #15
danflanagan8There were a couple failures:
and
Comment #16
danflanagan8Looks lik the LB failure is a known rando:
see #3477586: [random test failure] LayoutBuilderBlocksTest::testBlockPlaceholder failing or #3486986: [random test failure] Drupal\Tests\layout_builder\Functional\LayoutBuilderBlocksTest::testBlockPlaceholder
I think I have the Unit test fixed.
Comment #17
smustgrave commentedLeft some comments on the MR.
Comment #18
danflanagan8Comment #19
smustgrave commentedResolved the threads, can the issue summary get some quick eyes. Is that the proposed solution correct? Can the steps to reproduce section be added back.
Going to leave in review for additional eyes.
Comment #20
smustgrave commentedWill keep an eye out for this one.