Example #1
0
 /**
  * See _node_access_where_sql() for a non-views query based implementation.
  */
 public function query()
 {
     $account = $this->view->getUser();
     if (!$account->hasPermission('administer nodes')) {
         $table = $this->ensureMyTable();
         $grants = db_or();
         foreach (node_access_grants('view', $account) as $realm => $gids) {
             foreach ($gids as $gid) {
                 $grants->condition(db_and()->condition($table . '.gid', $gid)->condition($table . '.realm', $realm));
             }
         }
         $this->query->addWhere('AND', $grants);
         $this->query->addWhere('AND', $table . '.grant_view', 1, '>=');
     }
 }
 /**
  * Checks the node grants for the given operation.
  *
  * @param string $operation
  *   The operation to check the node grants for.
  *
  * @return string
  *   The string representation of the cache context.
  */
 protected function checkNodeGrants($operation)
 {
     // When checking the grants for the 'view' operation and the current user
     // has a global view grant (i.e. a view grant for node ID 0) — note that
     // this is automatically the case if no node access modules exist (no
     // hook_node_grants() implementations) then we don't need to determine the
     // exact node view grants for the current user.
     if ($operation === 'view' && node_access_view_all_nodes($this->user)) {
         return 'view.all';
     }
     $grants = node_access_grants($operation, $this->user);
     $grants_context_parts = [];
     foreach ($grants as $realm => $gids) {
         $grants_context_parts[] = $realm . ':' . implode(',', $gids);
     }
     return $operation . '.' . implode(';', $grants_context_parts);
 }
Example #3
0
 /**
  * {@inheritdoc}
  */
 public function alterQuery($query, array $tables, $op, AccountInterface $account, $base_table)
 {
     if (!($langcode = $query->getMetaData('langcode'))) {
         $langcode = FALSE;
     }
     // Find all instances of the base table being joined -- could appear
     // more than once in the query, and could be aliased. Join each one to
     // the node_access table.
     $grants = node_access_grants($op, $account);
     foreach ($tables as $nalias => $tableinfo) {
         $table = $tableinfo['table'];
         if (!$table instanceof SelectInterface && $table == $base_table) {
             // Set the subquery.
             $subquery = $this->database->select('node_access', 'na')->fields('na', array('nid'));
             // If any grant exists for the specified user, then user has access to the
             // node for the specified operation.
             $grant_conditions = static::buildGrantsQueryCondition($grants);
             // Attach conditions to the subquery for nodes.
             if (count($grant_conditions->conditions())) {
                 $subquery->condition($grant_conditions);
             }
             $subquery->condition('na.grant_' . $op, 1, '>=');
             // Add langcode-based filtering if this is a multilingual site.
             if (\Drupal::languageManager()->isMultilingual()) {
                 // If no specific langcode to check for is given, use the grant entry
                 // which is set as a fallback.
                 // If a specific langcode is given, use the grant entry for it.
                 if ($langcode === FALSE) {
                     $subquery->condition('na.fallback', 1, '=');
                 } else {
                     $subquery->condition('na.langcode', $langcode, '=');
                 }
             }
             $field = 'nid';
             // Now handle entities.
             $subquery->where("{$nalias}.{$field} = na.nid");
             $query->exists($subquery);
         }
     }
 }
Example #4
0
/**
 * Perform alterations to a structured query for a given tag.
 *
 * @param $query
 *   An Query object describing the composite parts of a SQL query.
 *
 * @see hook_query_alter()
 * @see node_query_node_access_alter()
 * @see QueryAlterableInterface
 * @see SelectQueryInterface
 */
function hook_query_TAG_alter(QueryAlterableInterface $query)
{
    // Skip the extra expensive alterations if site has no node access control modules.
    if (!node_access_view_all_nodes()) {
        // Prevent duplicates records.
        $query->distinct();
        // The recognized operations are 'view', 'update', 'delete'.
        if (!($op = $query->getMetaData('op'))) {
            $op = 'view';
        }
        // Skip the extra joins and conditions for node admins.
        if (!user_access('bypass node access')) {
            // The node_access table has the access grants for any given node.
            $access_alias = $query->join('node_access', 'na', '%alias.nid = n.nid');
            $or = db_or();
            // If any grant exists for the specified user, then user has access to the node for the specified operation.
            foreach (node_access_grants($op, $query->getMetaData('account')) as $realm => $gids) {
                foreach ($gids as $gid) {
                    $or->condition(db_and()->condition($access_alias . '.gid', $gid)->condition($access_alias . '.realm', $realm));
                }
            }
            if (count($or->conditions())) {
                $query->condition($or);
            }
            $query->condition($access_alias . 'grant_' . $op, 1, '>=');
        }
    }
}
Example #5
0
 /**
  * Adds a node access filter to a search query, if applicable.
  *
  * @param \Drupal\search_api\Query\QueryInterface $query
  *   The query to which a node access filter should be added, if applicable.
  * @param \Drupal\Core\Session\AccountInterface $account
  *   The user for whom the search is executed.
  *
  * @throws \Drupal\search_api\SearchApiException
  *   Thrown if not all necessary fields are indexed on the index.
  */
 protected function addNodeAccess(QueryInterface $query, AccountInterface $account)
 {
     // Don't do anything if the user can access all content.
     if ($account->hasPermission('bypass node access')) {
         return;
     }
     // Gather the affected datasources, grouped by entity type, as well as the
     // unaffected ones.
     $affected_datasources = array();
     $unaffected_datasources = array();
     foreach ($this->index->getDatasources() as $datasource_id => $datasource) {
         $entity_type = $datasource->getEntityTypeId();
         if (in_array($entity_type, array('node', 'comment'))) {
             $affected_datasources[$entity_type][] = $datasource_id;
         } else {
             $unaffected_datasources[] = $datasource_id;
         }
     }
     // The filter structure we want looks like this:
     //   [belongs to other datasource]
     //   OR
     //   (
     //     [is enabled (or was created by the user, if applicable)]
     //     AND
     //     [grants view access to one of the user's gid/realm combinations]
     //   )
     // If there are no "other" datasources, we don't need the nested OR,
     // however, and can add the "ADD"
     // @todo Add a filter tag, once they are implemented.
     if ($unaffected_datasources) {
         $outer_conditions = $query->createConditionGroup('OR', array('content_access'));
         $query->addConditionGroup($outer_conditions);
         foreach ($unaffected_datasources as $datasource_id) {
             $outer_conditions->addCondition('search_api_datasource', $datasource_id);
         }
         $access_conditions = $query->createConditionGroup('AND');
         $outer_conditions->addConditionGroup($access_conditions);
     } else {
         $access_conditions = $query;
     }
     if (!$account->hasPermission('access content')) {
         unset($affected_datasources['node']);
     }
     if (!$account->hasPermission('access comments')) {
         unset($affected_datasources['comment']);
     }
     // If the user does not have the permission to see any content at all, deny
     // access to all items from affected datasources.
     if (!$affected_datasources) {
         // If there were "other" datasources, the existing filter will already
         // remove all results of node or comment datasources. Otherwise, we should
         // not return any results at all.
         if (!$unaffected_datasources) {
             // @todo More elegant way to return no results?
             // @todo Now that field IDs can be picked freely, this can theoretically
             //   even fail! Needs to be fixed!
             $query->addCondition('search_api_language', '');
         }
         return;
     }
     // Collect all the required fields that need to be part of the index.
     $unpublished_own = $account->hasPermission('view own unpublished content');
     $enabled_conditions = $query->createConditionGroup('OR', array('content_access_enabled'));
     foreach ($affected_datasources as $entity_type => $datasources) {
         foreach ($datasources as $datasource_id) {
             // If this is a comment datasource, or users cannot view their own
             // unpublished nodes, a simple filter on "status" is enough. Otherwise,
             // it's a bit more complicated.
             $status_field = $this->findField($datasource_id, 'status', 'boolean');
             if ($status_field) {
                 $enabled_conditions->addCondition($status_field->getFieldIdentifier(), TRUE);
             }
             if ($entity_type == 'node' && $unpublished_own) {
                 $author_field = $this->findField($datasource_id, 'uid', 'integer');
                 if ($author_field) {
                     $enabled_conditions->addCondition($author_field->getFieldIdentifier(), $account->id());
                 }
             }
         }
     }
     $access_conditions->addConditionGroup($enabled_conditions);
     // Filter by the user's node access grants.
     $node_grants_field = $this->findField(NULL, 'search_api_node_grants', 'string');
     if (!$node_grants_field) {
         return;
     }
     $node_grants_field_id = $node_grants_field->getFieldIdentifier();
     $grants_conditions = $query->createConditionGroup('OR', array('content_access_grants'));
     $grants = node_access_grants('view', $account);
     foreach ($grants as $realm => $gids) {
         foreach ($gids as $gid) {
             $grants_conditions->addCondition($node_grants_field_id, "node_access_{$realm}:{$gid}");
         }
     }
     // Also add items that are accessible for everyone by checking the "access
     // all" pseudo grant.
     $grants_conditions->addCondition($node_grants_field_id, 'node_access__all');
     $access_conditions->addConditionGroup($grants_conditions);
 }