How to Make OG and TAC Work Together: Step 2

Events happening in the community are now at Drupal community events on www.drupal.org.
somebodysysop's picture

Notes as of OGR Release 3.0 and higher

This has been a long process. In short, I've been able to get TAC (Taxonomy Access Control) and OG (Organic Groups) working together with OGR (Organic Groups User Roles). The history of this process is discussed below under Notes previous to OGR Release 3.0. I feel it is important to maintain this documentation. If you are considering using TAC/OG Integration, you should read it to understand the background and important issues of this project.

The latest progress on this project involves use of the "Multiple Node Access logic patch" which is discussed at length here: http://drupal.org/node/196922

Instructions and patch locations for installing current OGR TAC/OG Integration are located here: http://groups.drupal.org/node/4026

Please submit any questions you may have regarding this project in the Issues for OG User Roles: http://drupal.org/project/issues/og_user_roles?categories=support&states...

Notes previous to OGR Release 3.0

At first, I was going to provide the patches for the module updates in this step, but this is a big step because here is where you modify all the access control mechanisms. I wanted to break this down into smaller steps, but it's pretty difficult since all the changes have to be done at once. So, I decided to make this step an educational step designed to share my philosophy and approach to the access control changes I made, and how they came about.

To recap, I needed OG (Organic Groups) and TAC (Taxonomy Access Control) to work together. In the default Drupal access control setup, if you have a node that is in a group and has a particular taxonomy, any user can see the node if he EITHER belongs to the group OR has access to the taxonomy term. What I wanted was a mechanism that only allowed access to the node if the user BOTH belongs to the group AND has access to the taxonomy term.

This discussion with the TAC maintainer was very instrumental in pointing me in the right direction to achieve my goal: http://drupal.org/node/122712. It also helped to make clear what I was dealing with:

There are basically two major elements of access control: grants and permissions (this is my terminology). Grants are things like "grant_list", "grant_view", "grant_update", "grant_delete", and are generally assigned through taxonomy. Permissions are assigned to roles via the Drupal "access control" menu, and typically are things like "access content", "create document content", "administer organic groups".

There are three functions which are primarily used to determine what access users have to content: "user_access" (from the user.module) and "node_access" (from the node.module) and db_rewrite_sql (a module hook). "user_access" deals primarily with permissions but "node_access" looks at permissions and grants. db_rewrite_sql handles access with respect to node listings.

Note: I know that there are those of you who are going to mention things like "taxonomy_access_node_access_records($node)" and "hook_node_access_records($node)" and "hook_node_grants", etc... But, not matter how I look at it, the access control always seems to come down to "user_access", "node_access" and "db_rewrite_sql". Bringing back a load of grants with no way to establish which have priority over which just doesn't seem to solve the problem.

So, to recap, "create" access is usually determined by "user_access" function. Node "view", "update" and "delete" access by "node_access". And, node listing by "db_rewrite_sql". So, with respect to access control modification, these are the Drupal core functions I need to be able to change.

I have already modified "user_access" with my OG User Roles module which allows granting of role permissions by group. The next step was to modify "node_access" for viewing, updating and deleting content while respecting both OG and TAC grants. Enter the "Extensible Node Access/Authorisation Capability" patch: http://drupal.org/node/122173. Read up on this because this is the core of my modifications.

Using the "Extensible Node Access/Authoriisation Capability" patch, I was able to modify "node_access" to use a "nodeapi" hook that allowed me to write access control code that made sure that both OG and TAC grants were respected.

If Drupal node listings utilized "user_access", my problem would have been solved right here. Unfortunately it does not. For node listing access, I had to look to "node_db_rewrite_sql". This seemed crazy to me: After all the work I did with the access nodeapi hook, I still had to turn around and basically re-write node_db_rewrite_sql to do the same thing the access nodeapi was doing. However, there was no way around this: I needed to modify this function if I wanted my node listing to reflect both OG and TAC access controls. Actually, Drupal states (in the "node_access" comments) that this seemingly inexplicable inconsistency is for performance reasons, but I think this is what makes it near impossible for contributors to write modules whose access controls respect each other and work in concert. This is my opinion only.

After modifying "node_db_rewrite_sql" for the new access control, I pretty much had everything working, with the exception of one problem: My vocabulary pulldown select lists within nodes didn't seem correct. They were either missing vocabulary terms, or listing terms that should not be there. The taxonomy pulldown lists are created by "taxonomy_form_alter" (in the taxonomy.module), but if you have the taxonomy_access.module (TAC) installed, the access for this list is controlled by "taxonomy_access_db_rewrite_sql". So, I also needed to modify the "taxonomy_access_db_rewrite_sql" function in the Taxonomy Access Control module to respect OG and TAC together.

After these modifications, I had a system that worked as I wanted: People can only see the content they have access to see. I can have dozens of groups without having to define dozens of dozens of roles - each group can use the same roles because users role access can be defined by group (or site wide). Furthermore, within the groups, I can define further restrictions to content using taxonomy.

The only drawback to this system is that all content must have taxonomy and either belong to a OG group, or be explicitly marked as "public" to be seen. Obviously, these modifications are for a site that is OG-centric and security minded. If your site does not primarily consist of multiple groups which contain highly private content, then you should not waste your time on these modifications.

Below is the list of modules I have installed, and the modifications to each that I have made. These are notes I made as I went through this process. Essentially, the core modifications are limited to just three modules: node, og and taxonomy_access. This is so you will know what to expect when you get to Step 3 - the patches:

• Forums
(None of these modifications required for access control)
Modified: theme_forum_display($forums, $topics, $parents, $tid, $sortby, $forum_per_page) Added functionality to use content submission page CSP “addform” node to create forum topics. Also put in group context on group forum “General discussion” page. (These are customizations and not necessary for access control)

• Node (updated).
Modified: Installed Extensible Node Access/Authorisation Capability patch: http://drupal.org/node/122173 in node_access() function.
Modified: db_node_rewrite_sql(),_node_access_join_sql(),_node_access_where_sql()

• NodeFamily
Had to modify php.ini: allow_call_time_pass_reference = On

• NodeProfile
Tutorial here: http://drupal.org/node/130489 and here http://drupal.org/node/130756
To display node profiles as profile categories (in “my account”): http://drupal.org/node/84541
Had to apply the patch as well as implement modification discussed in #31.
Permissions required to get one role to edit all uprofiles, and user to only be able to edit his own: authenticated role: ignore VUD|Create/List checked. User Profile Admin role: allow VUD|Create/List checked.

• OG
Ran into problems here: http://drupal.org/node/122385 and here: http://drupal.org/node/116756
Using TAC, if user role matches node vocabulary, user can see node even if he is not in the node’s group. That’s not good.

Possible solution: Extensible Node Access : http://drupal.org/node/122173

Added: Added og_node_access() function.
Modified: og_nodeapi() and og_db_rewrite_sql() functions.

(Below are my own customizations not necessarily related to access control)

Modified: og_og_create_links($group) function to use addform (custom node creation content submission CSP page).
Modified: og_form_add_og_audience() function. This changes puts a value in gids on node edits, which causes OG Config to respect the “Audience checkbox” on content edit. That is, if “Audience checkbox” is unchecked, then NO checkbox is presented on content edit (before this modification, the checkboxes would not appear on content creation, but would appear on content edits).
Modified: og_search_form($group) to say “Search Group”. Makes it a little less confusing.

• OG Forum (required for og_user_roles)

• OG User Roles (custom module updated from 4.7: SDL)
Using this format to create documents:

http://clients.mysite.com/node/addform?type=document&gids[]=12
(where '12' = groupID)
Note: When users get “access denied” using the above url, it’s usually because the addform node (node/20) contains vocabulary that has been updated. The node itself needs to be re-saved with “public” box clicked on OR all groups checked (so all group users can use it).

Added these functions: expand_checkbox_columns($element), og_user_roles_elements() for multi column checkboxes as per: http://drupal.org/node/41936

• Taxonomy
Note: “Categories” pulldown menu of vocabulary terms is created in taxonomy_form_alter. The db_rewrite_sql is actually handled by taxonomy_access_db_rewrite_sql.

• Taxonomy Access
(allow access according to roles – this will be used for documents)
Discovered that I need to set to “Deny” (not ignore) all permissions that are NOT allowed in a role. That is, if the role can list Term 1 but not Term 2, then Term 2 must be specifically “Deny”-ed. This is discussed in TAC Help: http://clients.mysite.com/?q=admin/help/taxonomy_access
Also here: http://drupal.org/node/68883

Added: taxonomy_access_node_access() function.
Modified: taxonomy_access_nodeapi() and taxnonomy_access_db_rewrite_sql() functions.
Modified: function taxonomy_access_node_grants($user, $op) (to use user_all_roles_array($user))

• User (updated)
Modified: user_access
Added: user_all_roles($user), user_all_roles_array($user), getgid($nodeID, $uid), user_table_exists($table).

• UserNode
Don’t forget to set permissions – Give Authenticated users node: create uprofile / edit own uprofile and usernode: edit own usernode.

• Views
Modified: views_taxonomy.inc: Exposed “user_roles” and “term_access” tables to Views.
Modified: views_upload.inc: Created field to show file attachment descriptions instead of filenames.

Comments

just a reference

chrisroditis's picture

to this:

• OG User Roles (custom module updated from 4.7: SDL)
Using this format to create documents:

http://clients.mysite.com/node/addform?type=document&gids[]=12
(where '12' = groupID)
Note: When users get “access denied” using the above url, it’s usually because the addform node (node/20) contains vocabulary that has been updated. The node itself needs to be re-saved with “public” box clicked on OR all groups checked (so all group users can use it).

it is nice to cite once again the code you need for this addform node, that was mentioned here

Essentially you create a node of type "page" where in it's body you paste the following(somebodysysop's) code and set the input format to 'php code'.

<?php
//
// Content Submission Code (Version 5.x)
//
// Put this in the node you will call for creating nodes using og user roles.
//
// node/addform is alias for my node/20
//
// You should alias whatever node you create using this code to:
//
//         node/addform
//

global $user;
$account = $user;
$gids = $_GET['gids'];
$typeFound = 'no';

//
// First, get the group ID and set the group context in case it's not already set
//
   
if ($gids) {
      
$group_node = node_load($gids[0]);
      
og_set_group_context($group_node);
    }

//
// Get the content type
//
   
$type = $_GET['type'];

if (
$type) {

if (
$type == 'forum') {
   if (
user_access('create forum topics')) { // This is my modified user_access which determines permissions based upon group role(s)
    
$typeFound = 'yes';
    
$output = node_add('forum');  // this always works
  
}
}

if (
$type == 'event') {
   if (
user_access('create events')) {
    
$typeFound = 'yes';
    
$output = node_add('event');
   }
}

if (
$typeFound == 'no') {
   if (
user_access('create '. $type . ' content')) {
    
$typeFound = 'yes';
    
$output = node_add($type);
   }
}

}

return
$output;
?>

You need to create an alias for this specific node. For this you need to have the path module(core) enabled. Once you enabled it if it is not already enabled, edit the node you just created and in "URL path settings" type "node/addform".

this code works for content types "event" and "forum". If you want it to work for e.g audio you will need to add another if statement among these:
if ($type == 'audio') {
if (user_access('create audio')) {
$typeFound = 'yes';
$output = node_add('audio');
}
}

Now when you want a user that belongs to a group to create an audio node, assuming the group administrator has given him access to create audio nodes in this group using "OG User Roles' module, you simply call this url:
http://www.mydrupalsite.com/node/addform?type=audio&gids[]=12

where audio is your content type and gids is the group id the user is trying to post content in.

I hope this helps somebody!

By the way, somebodysysop, did you find what is causing the access denied on node/add ? Must be a tough one, wish I could at least grasp the basics of access control so that I could help you.

{never give up}

A healthy disregard for the impossible.

Resolved this issue with ognodeadd

somebodysysop's picture

I decided to put the content creation code inside of OG User Roles itself. The new code uses "hook_access" to let the node's module determine the permissions, so you don't have to worry about manually creating code to handle specific content types.

<?php
/**
* Create content
* Format: http://www.scbbs.com/node/ognodeadd?type=link&gids[]=29
*/
function og_user_roles_ognodeadd() {
  global
$user;

 
$roles = og_user_roles_all_roles($user); // This returns normal $user->roles and includes OG roles if any

 
$user->roles = $roles;
 
$gids = $_GET['gids'];
  if (
$gids) {
    
$group_node = node_load($gids[0]);
    
og_set_group_context($group_node);
  }

 
$type = $_GET['type'];

  if (
$type) {
   
// Got this from node.module (node_access)
    // No matter the type, this should return us the create permission.
   
$module = node_get_types('module', $type);

    if (
$module == 'node') {
     
$module = 'node_content'; // Avoid function name collisions.
   
}

   
$access = module_invoke($module, 'access', 'create', $type);

    if (
$access === TRUE) {
     
$output = node_add($type);
    }
    else {
     
$output = 'Access denied.';
     
watchdog('access denied', 'node/ognodeadd?type='. $type .'&gids[]='. $gids[0], WATCHDOG_WARNING);
    }
  }

  return
$output;
}
?>

No dash conversion in type name

valeriod's picture

After $type = $_GET['type']; you need to convert the dashes back into underscores otherwise if the content type contains underscores it will not match and you get and Access Denied.

somebodysysop's picture

As of the 2.0 release of OG User Roles, only one patch will be required for TAC/OG integration.

As of this release, all access control code for TAC/OG integration is now built into the OG User Roles module. Only one patch is now required for this integration, the Nodeapi Access patch, and it is located here:

http://drupal.org/files/issues/nodeapi_access_4.patch

It is our hope that this patch will make it's way into Drupal 7 Core. See the discussions on it here: http://drupal.org/node/143075 and also here: http://drupal.org/node/122173.

A copy of this patch is also included in the OG User Roles 2.0 and higher distributions.

somebodysysop's picture

A new patch will be required for TAC/OG Integration as of OGR Release 5.x-3.0. It is the "Multiple Node Access logic patch" which is discussed at length here: http://drupal.org/node/196922.

I tried my best to be able to do this without patching any modules, but at this time, accomplishing this degree of multinode access is simply not possible in Drupal core without some patching. Fortunately, I've been able to keep it down to one. As you can see from the discussion, the effort is to get this functionality into a future Drupal core version. Hoping for D7, but we'll see.

The good thing about this new patch is that it utilizes the existing Drupal core node grants mechanism to achieve the desired integration. This, as opposed to the previous patch which utillized the unsupported hook_nodeapi('access') scheme, as well as a bloated hook_db_rewrite_sql() architecture.

All in all, I'm very happy with the direction TAC/OG Integration has taken with this new patch, and I think those of you who utilize this integration will be happy as well.

Instructions and patch locations for installing current OGR TAC/OG Integration are located here: http://groups.drupal.org/node/4026

Please submit any questions you may have regarding this project in the Issues for OG User Roles: http://drupal.org/project/issues/og_user_roles?categories=support&states...

Access Control

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds:

Hot content this week