If the user doesn't have the "Administer orders" permission then when applying a filter to /jsonapi/commerce_order/default the result is always empty.

Example: /jsonapi/commerce_order/default?filter[state]=completed

"View own orders" should be enough to return filtered results.

CommentFileSizeAuthor
#4 3134493-4.patch1.17 KBskyredwang

Issue fork commerce-3134493

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

introfini created an issue. See original summary.

mglaman’s picture

Status: Active » Postponed (maintainer needs more info)

This should be fixed with the latest Entity API release which fixed the JSON:API security layer with existing Entity API permission setup. Can you let me know if this is still broken?

skyredwang’s picture

Status: Postponed (maintainer needs more info) » Active

See the discussion below, @mglaman pin pointed the cause, and have a solution in mind.

So the problem is when you're a regular user and trying to view your like order history correct?

mglaman:centarro:  44 minutes ago
I'm opening the code right now to see if I can think of anything off the top of my head

mglaman:centarro:  44 minutes ago
 *     "query_access" = "Drupal\commerce_order\OrderQueryAccessHandler",

mglaman:centarro:  43 minutes ago
Oh shoot I think I know why, it's because we don't implement entity owner interface

mglaman:centarro:  43 minutes ago
I think we need to add an additional hook inside commerce order that supports the whole customer owner of the order bit

mglaman:centarro:  42 minutes ago
see entity_jsonapi_entity_filter_access

mglaman:centarro:  42 minutes ago
      elseif ($owner_key && $condition->getField() === $owner_key && $condition->getOperator() === '=' && $condition->getValue() === $account->id()) {
        $result[JSONAPI_FILTER_AMONG_OWN] = $allowed;
      }

mglaman:centarro:  42 minutes ago
  elseif ($conditions->count() === 1 || $conditions->getConjunction() === 'OR') {
    $published_key = $entity_type->getKey('published');
    $owner_key = $entity_type->getKey('owner');

mglaman:centarro:  41 minutes ago
I think we're hitting
        // Unsupported condition, no access can be granted.
        return [];

mglaman:centarro:  41 minutes ago
so commerce_order.module needs to do hook_jsonapi_entity_filter_access and support $result[JSONAPI_FILTER_AMONG_OWN] directly

mglaman:centarro:  41 minutes ago
Does that make sense?

mglaman:centarro:  41 minutes ago
It seems like the most probable cause of the issue you're seeing

skyred  40 minutes ago
As a normal user/customer, I can visit /jsonapi/commerce_order/default and see my order list, but I just can't use any filter

mglaman:centarro:  40 minutes ago
I need to step away my lunch but I will keep an eye out here and follow up

skyred  40 minutes ago
I am reading your comments above now

mglaman:centarro:  40 minutes ago
Yeah the filter is not working it's got to be due to the lack of an owner key

skyred  15 minutes ago
Would you like me to submit a patch for commerce_order.module?

skyredwang’s picture

StatusFileSize
new1.17 KB

I wrote this patch below. But, it doesn't seem to solve the problem, and the code is not even called by JSON:API.

skyredwang’s picture

Status: Active » Needs work

I used commerce_order_jsonapi_commerce_order_filter_access hook instead, then it gets called. I debugged the return of the function, the result is good. However, filter in JSON:API still doesn't return anything.

mglaman’s picture

The generic is hook_jsonapi_entity_filter_access and specific entity overrides in hook_jsonapi_ENTITY_TYPE_filter_access. jsonapi.module actually does this. So we need commerce_order_jsonapi_commerce_order_filter_access.

skyredwang’s picture

I did try that, here is the problem

https://git.drupalcode.org/project/drupal/-/blob/8.9.x/core/modules/json...

L347 $access_results["filter_among_own"] is allowed, but

L387 still expects owner key for non-user entity, and $access_results["filter_among_own"] isn't checked until it finds the owner.

So, I am guessing this hook won't help us solve the problem?

mglaman’s picture

Assigned: Unassigned » mglaman

Working on this! It is vital for customer order history pages.

mglaman’s picture

As @skyredwang has pointed out, the hook results used in \Drupal\jsonapi\Access\TemporaryQueryGuard::getAccessConditionForKnownSubsets will not do us any good. This supports the following entity keys for mapping:

  • published
  • status
  • owner

If no conditions are set, the query access is marked as static::alwaysFalse($entity_type);.

This result is used in \Drupal\jsonapi\Access\TemporaryQueryGuard::getAccessCondition.

    // Get the condition that handles generic restrictions, such as published
    // and owner.
    $generic_condition = static::getAccessConditionForKnownSubsets($entity_type, $current_user, $cacheability);

Since orders do not have an owner entity key, the JSONAPI_FILTER_AMONG_OWN access result is ignored.

However, order's actually have entity query access through Entity API. So we can choose to bypass the TemporaryQueryGuard provided by JSON:API. I think the correct fix is to make JSONAPI_FILTER_AMONG_ALL allowed.

    // No conditions are needed if access is allowed for all entities.
    $cacheability->addCacheableDependency($access_results[JSONAPI_FILTER_AMONG_ALL]);
    if ($access_results[JSONAPI_FILTER_AMONG_ALL]->isAllowed()) {
      return NULL;
    }

If it is allowed, then the entire JSON:API layer that intends to create an entity query access layer is bypassed.

This should allow \Drupal\commerce_order\OrderQueryAccessHandler to do its job.

mglaman’s picture

Assigned: mglaman » Unassigned
Status: Needs work » Needs review

I got ahead of myself and ruined the test only run. DrupalCI queues after each commit, but it runs ahead the merge request's branch HEAD. Not each commit.

Either way, this seems to be the right fix!

skyredwang’s picture

Status: Needs review » Reviewed & tested by the community

It works well!

mglaman’s picture

Assigned: Unassigned » mglaman
Status: Reviewed & tested by the community » Needs work

I want to add test coverage for an admin filtering and anonymous users. Then I think we can commit.

introfini’s picture

It's working. Thanks!

mglaman’s picture

Assigned: mglaman » Unassigned
Status: Needs work » Needs review

Okay, in https://git.drupalcode.org/project/commerce/-/merge_requests/5/diffs?com... I have expanded test to

  • Order customer can only see their orders and filter them (existing test.)
  • Other customer can view their orders only
  • Guest user cannot find any orders
  • Guest user, with view own commerce_order cannot find any orders
  • Admin and view commerce_order can find all orders.
mglaman’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC per @skyredwang in #12, confirmed by @introfini in #14!

  • mglaman committed dc29aad on 8.x-2.x
    Issue #3134493 by skyredwang, mglaman, introfini: The user needs "...
mglaman’s picture

Status: Reviewed & tested by the community » Fixed

🥳 Committed!

Status: Fixed » Closed (fixed)

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