Node access

in Drupal 7

About me

  • Daniel Popdan
  • Drupal experience ~ 1,5 years
  • 13 domains
  • 1 Drupal site
  • Domain access
  • Organic groups

Node access

  • Determines who can do what to wich nodes
  • Operations:
    • CREATE
    • VIEW
    • UPDATE
    • DELETE

What offers ?

  • Node access permission
  • Alter hooks
  • Access control modules
  • Node Access API modules

User permission - Node

  • CRUD on every content types
    • Article: Create new content
    • Article: Edit own content
    • Article: Edit any content
    • Article: Delete own content
    • Article: Delete any content
  • Bypass content access control
hook_node_acess($node, $op, $account)
  • Can be implemented by any module
  • Used for access to individual nodes
  • Operations
    • 'create'
    • 'view'
    • 'update'
    • 'delete'
  • Return
    • NODE_ACCESS_ALOW (TRUE)
    • NODE_ACCESS_DENIED (FALSE)
    • NODE_ACCESS_IGNORE (NULL)
node_access($op, $node, $account = NULL)
  • Checks if the operation is valid
  • Gets the user and checks the cache
  • Checks for 'bypass node access'
  • Checks for 'access content'
  • Invokes hook_node_access();
  • Check for grants
/**
 *  Implements hook_node_access().
 */
function example_node_access($node, $op, $account) {
  // Check for the content type.
  if ($node->type == 'premium') {
    // Check for the operation.
    if ($op == 'create') {
      // Get the account wrapper.
      $account_wrapper = entity_metadata_wrapper('user', $account);
      // If is premium let see the content, else deny.
      if (!empty($account_wrapper->field_is_premium->value()) &&
        $account_wrapper->field_is_premium->value()) {
        return NODE_ACCESS_ALLOW;
      }
      else {
        return NODE_ACCESS_DENY;
      }
    }
  }

  return NODE_ACCESS_IGNORE;
}

Conclusion

  • Acts on Create, View, Update, Delete
  • No tables
  • No queries
  • Works on individual nodes
  • Can override other modules
  • I.e OG Groups - Domain Access

Node Access API

  • Uses {node_access} table
  • Create JOINs for return lists of nodes
  • Does not act on 'create' operation
$query->addTag('node_access');

! No tag => security violation

hook_node_access_records($node);
hook_node_grants($account, $op);

{node_access}

  • nid - The node.nid the reccord affects [int]
  • gid - The grant id [int]
  • realm - The realm [string]
  • grant_view - [0/1]
  • grant_update - [0/1]
  • grant_delete - [0/1]

hook_node_access_records

  • determines if a specific node should be locked
  • modules has the opportunity to create a Lock with a specific “realm” and “id”

hook_node_grants

  •  is called to create a “key-ring” for a particular user account
  • is called dynamically at each page load
hook_node_access_records($node)
node_save($node);
node_access_acquire_grants($node);
$grants = module_invoke_all('node_access_records', $node);
node_access_write_grants($node, $grants, NULL, $delete);
/**
 * Implements hook_node_access_records().
 */
function hook_node_access_records($node) {
  // We only care about the node if it has been marked private. If not, it is
  // treated just like any other node and we completely ignore it.
  if ($node->private) {
    $grants = array();
    // Only published nodes should be viewable to all users. If we allow access
    // blindly here, then all users could view an unpublished node.
    if ($node->status) {
      $grants[] = array(
        'realm' => 'example',
        'gid' => 1,
        'grant_view' => 1,
        'grant_update' => 0,
        'grant_delete' => 0,
        'priority' => 0,
      );
    }
    // For the example_author array, the GID is equivalent to a UID, which
    // means there are many groups of just 1 user.
    // Note that an author can always view his or her nodes, even if they
    // have status unpublished.
    $grants[] = array(
      'realm' => 'example_author',
      'gid' => $node->uid,
      'grant_view' => 1,
      'grant_update' => 1,
      'grant_delete' => 1,
      'priority' => 0,
    );

    return $grants;
  }
}
hook_node_grants($account, $op)
node_access_grants($op, $account = NULL)
  • Called by
hook_query_TAG_alter();
node_access();
node_access_view_all_nodes();
_node_query_node_access_alter();
/**
 * Implements hook_node_grants().
 */
function hook_node_grants($account, $op) {
  if (user_access('access private content', $account)) {
    $grants['example'] = array(1);
  }
  $grants['example_author'] = array($account->uid);
  return $grants;
}

hook_node_access_records_alter()

  • Change storage rules before they are written to the database 
  • Good for bridge
  • Alter the user's grants at request time

hook_node_grants_alter()

/**
 * Implements hook_node_access_records_alter().
 */
function hook_node_access_records_alter(&$grants, $node) {
  // Our module allows editors to mark specific articles with the 'is_preview'
  // field. If the node being saved has a TRUE value for that field, then only
  // our grants are retained, and other grants are removed. Doing so ensures
  // that our rules are enforced no matter what priority other grants are given.
  if ($node->is_preview) {
    // Our module grants are set in $grants['example'].
    $temp = $grants['example'];
    // Now remove all module grants but our own.
    $grants = array('example' => $temp);
  }
}

/**
 * Implements hook_node_grants_alter().
 */
function hook_node_grants_alter(&$grants, $account, $op) {
  // Our sample module never allows certain roles to edit or delete
  // content. Since some other node access modules might allow this
  // permission, we expressly remove it by returning an empty $grants
  // array for roles specified in our variable setting.

  // Get our list of banned roles.
  $restricted = variable_get('example_restricted_roles', array());

  if ($op != 'view' && !empty($restricted)) {
    // Now check the roles for this account against the restrictions.
    foreach ($restricted as $role_id) {
      if (isset($account->roles[$role_id])) {
        $grants = array();
      }
    }
  }
}
Made with Slides.com