I currently maintain a gallery module, called Juicebox, which integrates with some 3rd party javascript to deliver fluid/responsive galleries in Drupal. This module acts as a formatter for things like imagefields, and one of its tasks is to structure imagefield data as XML which can be fed to some client-side javascript for rendering.

This XML generation is a bit like what services does for numerous types of entities, but specifically for imagefields (and only one imagefield at a time). Rendering this XML is not too hard, as the request URL just has to pass-in things like the entity type, id, field name, etc. and the field/entity APIs offer easy functions to build the needed data. The trick is checking if the current user actually has view access to the field, and blocking the XML request with a 403 if not. I can check if a field-level restriction is in place with something like field_access() but this does not tell me if the entity that the field is attached to has any view restrictions.

Of course node_access() is any easy way to check entity-level access for nodes but the imagefield that we are building XML for could be attached to any kind of entity. The contrib "Entity" module has a generic entity_access() function that seems useful, but it will not work properly for core entity types (nodes, users, comments, etc.).

So I'm left thinking that the only way to deal with this is to build an access check function that has a switch (or something) that runs a different type of access check depending on what type of entity we are dealing with (one check for nodes, another for users, another for comments, etc.). This feels a bit sloppy and incomplete, but I have yet to find a better way. It does look like there will be a solution for this in Drupal 8 (see here) but I'm very interested to know what the best practice for this should be in Drupal 7.

Comments

rjacobs’s picture

Earlier I said:

The contrib "Entity" module has a generic entity_access() function that seems useful, but it will not work properly for core entity types (nodes, users, comments, etc.).

But upon further research it seems that this is not true. I see now that the Entity API module actually adds access callbacks to core entity types, making them work with the entity_access() function. So if Entity API is installed this function is actually a holistic solution. It seems that this is actually one of the exact problems that Entity API exists to solve.

So for general purposes I think this is solved. The only trick that remains for me is to decide if it's worth it to add a new dependency to my module just to add these access checks. I'm thinking of a hybrid solution where entity_access() will be used if it's available but some common entity types will still be checked if its not. Something like the following:

/**
 * Check view access for an arbitrary entity that contains a Juicebox gallery.
 *
 * @param string $entity_type
 *   The type of entity being checked (e.g. "node").
 * @param object $entity
 *   The full entity object that the Juicebox gallery field is attached to.
 * @return boolean
 *   Returns TRUE if view access is allowed for the current user or FALSE if
 *   not. If access cannot be confirmed, returns NULL.
 */
function _juicebox_check_entity_view_access($entity_type, $entity) {
  // If the Entity API module is installed we can use entity_access() to check
  // access for numerous entity types via their access callbacks. All core
  // entities, and many custom ones, can be handled here.
  if (module_exists('entity')) {
    return entity_access('view', $entity_type, $entity);
  }
  // If we can't do a check with entity_access() we only maintain checks for a
  // couple popular core entity types that provide thier own explicit access
  // functions.
  switch ($entity_type) {
    case 'node':
      return node_access('view', $entity);
    case 'user':
      return user_view_access($entity);
  }
  // Log a warning and return NULL if we can't do a conclusive check.
  watchdog('juicebox', 'Could not verify view access for entity type %type while building Juicebox XML. This may have resulted in a broken gallery display. You may be able to remove this error by installing the Entity API module and ensuring that an access callback exists for entities of type %type.', array('%type' => $entity_type), WATCHDOG_ERROR);
}
rjacobs’s picture

I'm marking this as solved.

From what I have been able to learn access checks in D7 need to be specific to the entity type. This can be managed via the appropriate "tags" at query time (though different entity types implement different tags) or via the appropriate access checking functions (which are also specific to entity type). The Entity API provides some nice helper methods to consolidate all this, bit in the end it's still limited by these realities, and can only help with core entity types or custom entities that explicitly define their own unique access callbacks.

In Drupal 8 things may be easier:
https://drupal.org/node/1696660