Problem/Motivation

Core automatically tags every Storage entity query with storage_access when accessCheck(TRUE) is used (Drupal\Core\Entity\Query\Sql\Query::execute() adds {entity_type_id}_access for any entity type), and StorageViewsData (via core's EntityViewsData) declares the same storage_access tag as the base table's "access query tag". Both are standard, dependency-free entry points Drupal core provides for exactly this purpose — but nothing in the Storage module currently implements hook_query_storage_access_alter() to act on that tag.

As a result:

  • \Drupal::entityTypeManager()->getStorage('storage')->getQuery()->accessCheck(TRUE)->execute() returns entities the current user cannot actually view, even though $entity->access('view') correctly denies them via StorageAccessControlHandler.
  • The Views field/filter defined in StorageViewsData for storage_access has the help text "Filter for data by view access. Not necessary if you are using storage as your base table," implying automatic filtering — but no such filtering happens, and the referenced filter plugin id (storage_access) doesn't correspond to any actual plugin class, so adding it in the Views UI produces a broken handler.

Steps to reproduce

  • Create a storage entity of any bundle, owned by user A.
  • As user B (not the owner, without a relevant "any"/"administer" permission), run:
\Drupal::entityTypeManager()->getStorage('storage')
  ->getQuery()
  ->condition('id', $entity->id())
  ->accessCheck(TRUE)
  ->execute();
  • The entity ID is returned, even though $entity->access('view') for user B returns FALSE.

Proposed resolution

Add a core-only hook_query_storage_access_alter() implementation (no third-party dependency — same pattern node module uses for hook_query_node_access_alter() / tag node_access) that translates StorageAccessControlHandler::checkAccess()'s 'view'-operation logic into query conditions: for each bundle, OR together status = 1 + "view published (bundle) storage entities", status = 0 + "view unpublished (bundle) storage entities", and status = 0 + owner match + "view own unpublished (bundle) storage entities", short-circuiting entirely for administer storage entities. Detect the base table the same way NodeDatabaseHooks::queryNodeAccessAlter() does (via $query->getTables() / a base_table metadata fallback), since Views may alias storage_field_data.

Once the tag is handled, remove the non-functional storage_access filter definition in StorageViewsData (or the "not necessary if..." help text becomes literally true and the explicit filter can simply be dropped for views on the storage base table).

Out of scope: this only covers the module's own baseline published/permission rules. Sites layering custom hook_entity_access() logic on specific bundles (e.g. owner/shared-list restrictions) would still need their own hook_query_storage_access_alter() to get that enforced at the query level — the same way node access modules must implement hook_node_grants() to participate in core's grants system.

Issue fork storage-3609288

Command icon 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

mandclu created an issue. See original summary.

mandclu’s picture

Title: EntityQuery::accessCheck(TRUE) does not enforce access for Storage entities — query_access handler exists but isn't wired up » EntityQuery::accessCheck(TRUE) doesn't filter Storage entities — add a query_storage_access_alter implementation
Issue summary: View changes

  • mandclu committed 5db7db73 on 1.4.x
    fix: #3609288 EntityQuery::accessCheck(TRUE) doesn't filter Storage...
mandclu’s picture

Status: Active » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.