Problem/Motivation
Symptom:
After saving an existing node or other entity, further access checks on that entity are incorrect for the remainder of the request.
Occurs more often when you have some custom access logic in hook_node_access(), hook_node_access_record(), hook_entity_access(), etc.
NOTE: This only happens with subsequent access checks within the same request.
Problem:
EntityAccessControlHandler statically caches calls to ::access(). There appears to be no invalidation of that cache when an entity is updated.
Steps to reproduce:
See patch with test.
Proposed resolution
Invalidate the static access cache (EntityAccessControlHandler::$accessCache) for an entity when the entity is updated.
It's not clear how/where that invalidation should happen.
Workaround:
Manually invalidate the entire static cache before subsequent access checks.
Drupal::entityTypeManager()->getAccessControlHandler('ENTITY_TYPE')->resetCache();
This can incur a performance hit since it resets the cache for ALL access checks.
| Comment | File | Size | Author |
|---|---|---|---|
| #14 | 2834344-14.patch | 4.52 KB | jhedstrom |
| #2 | drupal-entity-access-cache-TEST-2834344-1-do-not-test.patch | 2.26 KB | milesw |
Comments
Comment #2
milesw commentedThis patch contains a test that reproduces the issue.
Comment #3
milesw commentedHere is a patch to use hashes instead of UUIDs as cache keys. Could not find a decent way to invalidate the cache upon entities being saved, so this seems like a decent alternative. Test from original patch is included.
Comment #4
milesw commentedChanging status.
Comment #5
dawehnerIt would be really nice to document why we need all the values here. I could imagine that calling
$entity->toArray()is quite expensive actuallyComment #6
larowlanI agree with @dawehner
Comment #7
milesw commentedThanks for reviewing @dawehner. You're right,
$entity->toArray()is probably too expensive to use there. Especially since it includes computed properties.For the sake of performance, hashing entities is probably a bad approach here. Access checks can be called many, many times.
I'll investigate other possibilities, but it would be nice to get input from others more familiar with the entity system.
Comment #8
mlhess commentedComment #9
mlhess commentedComment #10
dawehnerI wonder whether it would be easier to key by
$uuid, $revision_id, $langcode, $changed_timeComment #12
jhedstromThis changes to utilize the cache keys mentioned by @dawehner. However, since the test entity isn't setting a new revision (id is coming back null), and doesn't implement
EntityChangedInterface, the cache key doesn't change on save, making the test fail. This would resolve the issue for entities implementing those 2 interfaces...Comment #14
jhedstromThis has the tests green. Since the
getCacheIdmethod could be overridden by entity types that do not implement changed or revisions, that could be customized as needed for other types...Comment #26
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #need-reveiw-queue. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge require as a guide.
Wonder if this is still an issue with the changes from this commit. https://git.drupalcode.org/project/drupal/-/commit/11ef44a7f767000930a25...
Sorry couldn't find the ticket for this
The current patch no longer applies but am wondering if it's been resolved.
Please do not just reroll till it's been confirmed still an issue.
Comment #28
smustgrave commentedPer #26
Comment #29
smustgrave commentedwanted to bump 1 more time before closing.