D8, just like D7, ships only with the node access API on the query level. Other entity types get nothing.

In D7, Commerce implemented its own query alters that added the conditions needed to respect access (limiting the product type or ids to the ones the current user is allowed to see). The "grants" approach that node access takes wasn't replicated, most core people familiar with node access aren't big fans of it.

While we can easily replicate the D7 Commerce approach of individual query alters, lets see if we can implement a slightly more generic API for all of contrib to use. I've asked Damien Tournoud to comment on how he thinks this should work, since he's very familiar with node access and wrote the Commerce query alters. He thinks we should try to imitate the cache context API:

[9:45 PM] Damien Tournoud: the ACL (grants) approach works for some use-cases, and miserably fails on others
one really annoying aspect of it is that it forces you to duplicate parameters that are already on the entity, for no good reason
For example: try to express "owners can see" in a ACL
you need a to give a "uid=<owner id>" access item to every entity, and give "uid=<uid>" grant to all users
[9:53 PM] Damien Tournoud: you probably want to introduce a lot more structure in there, if you want it to be efficient
It's really similar to the caching problem. If you think of access control as keys, the problem is to efficiently generate all the possible access control keys for a particular user, and use that to match the accessible entities but to be able to efficiently generate all the possible access control keys, you need more information upfront (which is what the cache context stuff provides).
On saving the entity, you would run the access facets of the bundle, for example X and Y. Each will give you a list of values. You would end up with X = [X1, X2, X3] and Y = [Y1, Y2]
You would save all the combinations of them
X1Y1, X1Y2, X2Y1, X2Y2, X3Y1, X3Y2
On performing a query for a particular entity type, you would run all the access facets that apply to this entity type. 
Here it's X, Y and Z. Each will give you a list of values.
You would expand all the subsets of them that apply to bundles of that entity type. In our case "X,Y", "Y,Z" and "Z".
That gives you a list of possible keys, and you run the query with that.
(facets being things such as uid, user role, entity bundle, etc)

Of course, access stays per bundle. The separation of keys between bundles allows us to reduce the number of possible combinations, but there might be some degenerated use cases. The best at this point would be to take the use cases of the few entity types of commerce and see if we are happy with that. The use cases will also dictate our storage decision (a field or a custom table). A field is loaded with an entity, so it's only feasible if the number of values is small.

So, the todo list goes like this:
1) Review node grants again. This article has a good explanation.
2) Review the Commerce 1.x implementation again.
3) Try to implement the new API using the Commerce 1.x use cases.

Ken Rickard also mentions he has something worth reviewing: https://twitter.com/agentrickard/status/605105820540338176

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

bojanz’s picture

bojanz’s picture

Work has been happening in the Entity API queue: #2909970: Implement a query-level entity access API.
(Done by dawehner, sponsored by Commerce Guys)

Unfortunately, due to encountered (and now fixed) permission bugs, we were unable to finish this functionality in time for Commerce 2.0, but there's always a future release.

joachim’s picture

There's also an issue in core for a new entity access system.

drugan’s picture

@joachim

What the issue? Please, share if you can.

joachim’s picture

drugan’s picture

Seems that the core issue has no any chance ever be committed. Unfortunately. So, we need to build our own DC access API. Or tweak with permissions here and there for each developer on their own.

Wim Leers’s picture

Issue tags: +Entity Field API
bojanz’s picture

Status: Closed (duplicate) » Active

Please don't close this. There will still be changes needed on the Commerce side (even if it's just adding the new handlers to the annotations), and they'll happen here. This issue is referenced from the Commerce roadmap.

bojanz’s picture

We've made good progress on #2909970: Implement a query-level entity access API. Expecting it to land within the next 2 weeks.

bojanz’s picture

Title: Create a query-level entity access API » Start using the entity query access API

It's time.

bojanz’s picture

Title: Start using the entity query access API » Start using the entity query access API on orders, products and stores

The fourth candidate was promotions, but they don't have a bundle nor an owner, and aren't rendered anywhere, so it seems pointless.

bojanz’s picture

Status: Active » Needs review
FileSize
3.26 KB

Initial patch. Still needs a custom query access handler for orders, to handle the non-standard "view own" permission that we have there.

Wim Leers’s picture

Exciting!

  • bojanz committed a6bcc3c on 8.x-2.x
    Issue #2499645 by bojanz: Start using the entity query access API on...
bojanz’s picture

Status: Needs review » Fixed

Added a custom handler for orders, and a QueryAccessSubscriber for carts. All now matching 1.x logic.

Note that stores have no "view own" permission. We can't make that assumption by default because it affects caching.
Sites that want to restrict store listings to only the user's store can implement a subscriber like this one:

<?php

namespace Drupal\yourmodule\EventSubscriber;

use Drupal\entity\QueryAccess\ConditionGroup;
use Drupal\entity\QueryAccess\QueryAccessEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class QueryAccessSubscriber implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      'entity.query_access.commerce_store' => 'onQueryAccess',
    ];
  }

  /**
   * Adds conditions for the "view own" permission.
   *
   * @param \Drupal\entity\QueryAccess\QueryAccessEvent $event
   *   The event.
   */
  public function onQueryAccess(QueryAccessEvent $event) {
    $conditions = $event->getConditions();
    $operation = $event->getOperation();
    $account = $event->getAccount();

    if ($operation != 'view') {
      return;
    }
    // The user already has full access due to a
    // "administer commerce_store" or "view commerce_store"
    // permission.
    if (!$conditions->count() && !$conditions->isAlwaysFalse()) {
      return;
    }

    // Or skip the permission check completely if you want
    // to always restrict the user to viewing their own store.
    if ($account->hasPermission('view own commerce_store')) {
      $conditions->addCacheContexts(['user']);
      $conditions->addCondition('uid', $account->id());
      $conditions->alwaysFalse(FALSE);
    }
  }

}
tormi’s picture

Status: Fixed » Closed (fixed)

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

lalop’s picture

I use to export orders via a drupal console command.
Since I haven't a connected account while running the query I now get an empty array now.

Louhichi Zied’s picture

hello,

This could be more useful if we had the Store object inside event, like traditional symfony events which provide the event subject,
to perform a final check of :

<?php $event->getStore()->getOwner() === $account->id(); ?>

Thx