I use ACL to restrict access to a specific node for a specific user.

The normal on my site is that all authenticated users should be granted view access. However, sometimes (this is rare) a specific user is disqualified from viewing a specific node, so I need to be able to remove view access for that node for that user.

ACL has enough fine-grained control to let me do this. However, ACL's default (which I seems to be unable to change) is that nobody has access. This means that every time I create a new node, I must manually grant access to all authenticated users on a one-by-one basis. This is very time consuming.

There is a People → Permissions page allow me to create default permissions for each Role. But there seems to be no similar page to create default permissions for each User.

I want to be able to define a default access list with users that has view access granted that is automatically applied whenever I create a new node that has per content node access control settings enabled. Then, only in the very rare cases where I want to depart from the default would I have to intervene to remove someone from the access list.

Comments

gisle’s picture

Issue summary: View changes

corrected typo

salvis’s picture

Status: Active » Closed (won't fix)

ACL is just an API module. It has no user interface and you cannot interact with it directly.

I don't know how you do what you're currently doing, but I assume that you're using an ACL client module that leverages ACL's functionality. It's that module's job to offer the functionality that you need, or you may have to develop an ACL client module yourself.

The Deny Access module might be a better match for your requirements.

gisle’s picture

Thanks for replying.

I am using ACL with the Content Access module. As I said initially, this combination can be used to set up the exact type of access list I want, it is just very awkward to do so because I can't find a way to automate things. I understand that you're saying that the functionality I am looking for (an UI to establish a default access list) should be added to Content Access, not ACL - so I'll pursue that.

I'll also take a look at Deny Access, but it does not look as it has the resolution (individual user and node) that I need.

If I take the route where I develop an ACL client module myself, where do I find the documentation of the API?

salvis’s picture

The problem with your concept is that it goes against the Drupal philosophy, which is OR access. Generally, you cannot "deny" access to a specific user, but you have to deny it to everyone and allow it to all-but-one.

It shouldn't be to hard to implement this in a custom ACL client. The ACL functions are pretty much documented inline. The best way to get the bigger picture is to look at an ACL client module -- I'd suggest to take Forum Access, which uses ACL to implement forum moderators. And by all means get DNA (in Devel), enable the debug mode and the second block.

gisle’s picture

Again, thank you for your time. DNA in Devel was really helpful for figuring out what goes on "under the hood".

For the record, I do not think my concept goes "against the Drupal philosophy". After all, ACL does what I want and it adheres to the Drupal philosophy. However I needed access to a suitable UI to control ACL, and the well respected Content Access client module did not offer that UI (for my application).

I think that I've found a client module with an UI that is usable. This is Flexi Access. It defaults to giving everyone access to the node, unless you choose to create a access control list for the node (then access becomes restricted to the users listed in the ACL). Not as flexible as being able to create a default ACL, but it will do.

salvis’s picture

Good, thanks for letting us know.

You may be able to encourage the Flexi Access author to add features to his module.

gisle’s picture

@salvis
thank you so much for you help so far.

I've started adding the functions I need to Flexi access.

Since Flexi access is an ACL client module, I first tried to implement these functions by only calling the ACL API functions. However, I could not figure out a way of doing this with the present ACL API.

However, I can do this by manipulating tables managed by ACL directly by means of the Drupal db abstraction layer (for an example, see the function flexiaccess_remove_acl_from node I've posted at the end of this message).

While this works (for now), I fully understand that this is not the right solution. A future release of ACL may change its table structure or its table semantics, in which case my client module will break horribly.

Can you offer any advice about what the correct "protocol" (Drupal-wise) is in cases like this. Do I have another go and work harder to get my code working with whatever the ACL API has to offer? Do I give up using the ACL module and set up and manage my own ACL tables instead? Do I submit a feature request to the ACL maintainer (i.e. you) and kindly ask for the missing functions to be added to the API? Or is the right solution something else altogether?

Any advice you can have in this matter will be much appreciated.

/**
 * Remove ACL from a node.  I.e. return the form's current node to the state where there
 * is no acl_user attached to the the node.  Leave the acl and acl_node tables alone.
 * Make sure node_access is reset to the default state.
 */
function flexiaccess_remove_acl_from node($form, &$form_state) {
  // Get nid of current node.
  $nid = $form_state['node']->nid;

  // Select acl_ids for this node.
  $query = db_select('acl_node', 'res')
  ->fields('res', array('acl_id'))
  ->condition('nid', $nid);
  $result = $query->execute();

  // Delete these acl_ids from acl_user table
  while($record = $result->fetchAssoc()) {
    $acl_id = $record['acl_id'];
    db_delete('acl_user')
    ->condition('acl_id',$acl_id)
    ->execute();
  }

  //  Reset node_access to the default state.
  $res = db_update('node_access')
    ->fields(array(
      'gid' => 0,
      'realm' => 'all',
      'grant_view' => 1,
      'grant_update' => 0,
      'grant_delete' => 0,
    ))
    ->condition('nid', $nid, '=')
    ->execute();

  cache_clear_all();

  drupal_set_message(t('Your ACL for this node has been removed.'));
}


salvis’s picture

ACL is designed to concurrently support multiple client modules. Every ACL record must have a module name (you pass the name of your module when you call acl_create_acl()), and acl_node_clear_acls($nid, $module) is the function you want to use to remove your ACL records.

NEVER change the {node_access} table directly. Call node_access_acquire_grants($node) instead.

salvis’s picture

Issue summary: View changes

missing article