Wednesday, January 30, 2013

Drupal permissions and the node_access table - a hard learned lesson

While building a custom filter for Views 2 on a Drupal 6 site I leaned an important lesson about the way Drupal handles permissions.

I was trying to write a filter that would display a selected list of nodes to users with a certain role.  Sounds easy right?  It would be fairly logical to assume that Drupal would support filtering access to nodes based on role. If you want to restrict access to an entire content type by role, this is easy. The 'views' explanation would be something like: "Show me nodes of this type, only to users who have this role".

My situation was different because the content type is accessible to all authenticated users, I only want to show a small subset of those nodes to users with a specific role.  That subset of nodes has no distinguishing property to filter, leading me to believe that I would have to write my own.

Here is where the trouble starts.

I wanted the filter to do a join between the 'node' table and the 'node_access' table to see if a particular node id was listed in the node_access table with the role id ( 'gid' in the table ) of the role to which I wanted to display the nodes. I was surprised when my queries were coming back empty.

I noticed that nodes of this content type would be returned with my custom filter when I used a role id that had access to nodes not available to 'authenticated users'.  To test this discovery I removed node access for authenticated users to the nodes I wanted available to the new role, and suddenly they were being listed in 'node_access' with the new role's id.

In summary:  If a node is accessible by the role 'authenticated user', the node_access table will only contain records associated with that role id.  Other roles given the same access will not have a record in the node_access table. This is most likely intended to reduce redundancy in the table because any user with any custom role will already be authenticated.

This is probably why this filter is not included in Views by default.

Unfortunately this means my query is impossible ( at least the way I attempted it ), and there goes several hours of facemashing my keyboard.

No comments:

Post a Comment