Right now we have products, orders, customer information profiles, and transactions all having their own set of permissions for viewing, editing, creating, deleting, and performing operations. None of these are pluggable, and some are just inferior. The main problem is they don't do a great job of allowing you to clearly provide permissions for the different tasks for different levels of administration and aren't extensible to allow modules to provide access using some rule other than straight permissions. This will be problematic especially for sites that allow peer-to-peer sales or fulfillment.

I want to start with a simple revamp of what we have, unifying perhaps through a central "entity access" API the way we define permissions for the various entities. This system should accommodate any number of tasks defined perhaps in the entity info - so it should be easy for a module to add an access check for refunding a particular type of transaction using hook_entity_info_alter() or something like that.

I'll think about this a little bit and am open to ideas, but I think this is essential prior to a 1.0. I'm already running into issues as I think through how to provide access to the various contextual links for operating on transactions.

Comments

Anonymous’s picture

subscribe

emptyvoid’s picture

I very interested in this topic, as I am starting research into the subject.

I am currently looking through the module contribution list to find an existing module to provide development support to.

I'm thinking a module could be created called: entity_access that provides a universal entity security API that integrates with entities, menu items, file API, and community modules like views, cck, and rules to name a few.

I'm posting my research and notes here: http://drupal.org/node/1067706

I'd welcome your thoughts and feedback on the subject.

rszrama’s picture

To elaborate on the initial issue a little more, after reviewing some of the access needs of our entities, it's not entirely clear to me that a single unified entity access system will be possible. It would at least need to be quite pluggable, and in some cases just not used. However, if we at least implement the following patterns for our various entity access functions, it'd be a start:

  1. The arguments should be $entity, $op, $account (which defaults to the current global $user), i.e. commerce_order_access($order, 'view').
  2. We should first check for general global permissions, i.e. "administer orders" or "Product: edit any product", that grant access regardless of individual permissions or account limitations.
  3. We should then check for general ownership permissions if possible, i.e. "Product: edit own products", that grant access to the user denoted as the owner of a given entity based on the entity's uid property.
  4. Last, we should pass the same arguments on to the hook of the same name as the access function, i.e. hook_commerce_order_access(). This hook should always receive the account variable because it will either be the original account passed in to the access check or a cloned $user variable.

It's important to note that these are OR steps, so we return TRUE as soon as possible and return FALSE only at the end if nothing else matches. Also, some of our entities won't necessarily have stand-alone access control. For example, line items don't have a uid. Line item access therefore is handled through the order access control system based on the $line_item->order_id property... so the line item access function will do little more than call commerce_order_access() with the line item's order object and the same $op and $account variables.

Now, I say the entity access is OR, but when it comes to API level delete access, we have to switch to AND. In other words, when checking to see if a product can be deleted, we want any module implementing the hook to tell the Product API that a particular product shouldn't be deletable (i.e. if it's referenced by a product line item). Same holds true for customer profiles. I'm not sure this applies to anything else aside from deleting, though.

Finally, there's the commerce_checkout_access() function that determines a particular user's access to the checkout page for a particular order. I don't believe this fits into either of the above systems, as access isn't based on cascading permissions but is still an OR. I do believe there's a separate issue dealing with cleaning up some of the complexity in commerce_checkout_access(), so let's just consider that out of scope for this present issue.

rszrama’s picture

Oh, and I should point out that I'm modeling entity owner permissions above on the node permissions where each node type is given a separate set of permissions starting with the name of the type so they're all grouped together. This is much better than the previous grouping according to operation and should be followed.

We'll be generating quite a bit of table bloat by separating product ownership permissions out by product type, but it's hardly a performance concern and is preferable to not having fine grained permissions. If it really becomes a problem, we can find some way to alleviate it through contrib later... at the very least figuring out a way to collapse the permissions tables (something which Admin Menu at least begins to do, though not entirely satisfactorily).

rszrama’s picture

lathan’s picture

Sub, I'm in need of such a solution. here was something I had put in my local branch http://drupal.org/node/1162046

Damien Tournoud’s picture

Status: Active » Needs review

This is basically done as far as I'm concerned and pending review.

Damien Tournoud’s picture

Assigned: Damien Tournoud » rszrama
rszrama’s picture

Status: Needs review » Fixed

Alrighty - committed and reviewed. Had to fix the customer profile update function name and gave the updates proper return values to provide information on the update screen.

See: http://drupalcode.org/project/commerce.git/commitdiff/f292d1b

Status: Fixed » Closed (fixed)
Issue tags: -dcsprint6, -rcblocker

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