We had made some modifications to Commerce permissions to make them more restrictive, and found that customers were no longer able to view line items on their order receipts.
It seems as though this issue has been discussed frequently over the years (see related links), but there has not been a clear description of what was causing the problem. We have investigated this thoroughly and I believe have a fairly clear picture of what is happening. As others have mentioned, the foundation of the problem is in the commerce_entity_access_query_alter function.
To provide context, we do not use any Commerce product as simply provided out of the box. Existing products are heavily modified, and we have created our own product entities to meet other needs. I believe this is part of the issue. Also we have chosen not to use the "Disable SQL rewrite" type of approach for the commerce_line_item_table view. This could very well solve the problem for many sites, but is not something we are interested in doing.
The core of the problem is the use of $conditions = db_or(); near the top of the function (see: https://git.drupalcode.org/project/commerce/-/blob/7.x-1.x/commerce.modu...). With this in place, there is an expectation that *something* needs to grant access, or the query will have an OR (1 = 0) added to the end, making it inaccessible.
Several entities are processed through commerce_entity_access_query_alter for the commerce_line_item_table view, including commerce_product. In our situation, we do not allow customers to have access to any View any or View own product entities. Only administrative users (admins, editors, contributors, etc.) have such permissions. However, our testing has shown the *only* way customers can see their own line items on an order receipt is to give them the View any <product_entity_name> product permission. Not even View own will work.
This really doesn't make any sense... why would we have to give "view any product" access to customers so they can see their order line items? I understand commerce_product needs to be processed for the view to support the "Commerce LIne Item: Product" relationship, but the end result does not work as expected when none of the permissions are in place.
The way we have worked around this is a terrible solution, but it works. The function has a drupal_alter to add hooks to look for condition additions/modifications. We forced the OR condition being generated by commerce_entity_access_query_alter to become an AND (1 = 1) using the following:
function hook_commerce_entity_access_condition_commerce_product_alter(&$conditions, $context) {
if (isset($context['account']) && $context['account']->uid > 0 && !isset($conditions->{'conditions:protected'}[0])) {
$conditions = db_and();
$conditions->condition('1', '1', '=');
}
}
This essentially says if the condition passed in does not already have a condition set, change OR to AND with a dummy condition of "1 = 1" so that it always evaluates to TRUE. This ensures the rest of the query can be processed as expected without failing due to no "View any
product" permissions.
I'd appreciate some additional feedback about this and what is ultimately recommended by the module owners. Thanks.
Comments
Comment #2
rszrama commentedHey Ron, good to hear from you! I think you've properly diagnosed the situation here, but I don't believe the core module should be changed. The reason is in the comments where we add that falsifying condition:
The key part there is the last sentence: checking to see if someone has access to view something is based on granting access (i.e. the assumption is you don't have access unless you're explicitly granted it) as opposed to access denial (i.e. the assumption is anyone should be able to see something unless there's a reason to prevent it). For entities that are private by default like orders, profiles, etc., it makes sense to be more restrictive by default and only grant access in defined cases.
This is really out of our hands. Views itself is responsible for adding the access to checks to its queries based on whatever relationships you add. The only way to avoid that is to disable SQL rewriting, which you've already discovered but ruled out.
The best advice I can offer is that it's probably more safe than you assume to disable SQL rewriting in these scenarios. You're basically saying to Views, "No, really, don't add any additional access checks to this query." And the assumption is that your own filters and / or contextual filters on the View will do the appropriate access granting for you.
For example, it's safe to disable SQL rewriting in the default "Line items" View, because it has a contextual filter applied that requires you to pass in the specific line item IDs that will be rendered by the View. When you add a relationship to products, this is the simplest, non-compromising solution there is.
If you need rewriting on for other reasons, I'd consider writing a new custom filter to apply whatever logic you're dependent on to your Views.