Introduction

This tutorial was inspired by an article "HowTo: Segment your site with access control" - see http://drupal.org/node/153686. But we take things a little bit further, describing a solution with even more fined-grained control using the same taxonomy-based approach. This first tutorial addresses the 'groups' functionality in our requirements. A second tutorial http://drupal.org/node/201673 adds powerful multisite functionality using exactly the same approach.

We need a solution with the following requirements:

  1. Separate content area for each group or department of an organization (private zone)
  2. Members of a group must be able to create any type of content
  3. Assign writers and editors to specific sections of an online publication, or create a locus of collaboration for each of organization's clients.
  4. Access to some content on each private part must be able to be limited to a group of people. Groups need to be able to have their own Group pages.
  5. Anonymous user can see only content marked as "Public"
  6. Authenticated user can view and create "Public" and "Restricted" content.

What all the above scenarios have in common is that they require access control--that is, access to certain parts of your site must be restricted to certain users.
In order to satisfy the group requirements you might come up with a pretty solution based on the Organic Groups family modules, installing at least 2-3 additional modules.
This tutorial describes an alternative, probably cleaner, solution for groups using the core taxonomy module and the contributed taxonomy_access modules
When building a site you must consider future changes and upgrades to next Drupal releases. Therefore it is better to use as much as possible from the Drupal core and as few as possible contributed modules. The updating of contributed modules can be very slow and sometimes the author of a module might even abstain from upgrading his module for a newer Drupal release.

This tutorial assumes a reader has a basic knowledge about drupal system.

Implementation

This tutorial will describe how to build the required solution step by step. There are 6 steps:

  1. Install Drupal.
  2. Install Taxonomy_access module.
  3. Categorize the site with the taxonomy module.
  4. Create user roles and assign users to the newly-created roles.
  5. Set role access control with the taxonomy_access module.
  6. Test.

The rest of this tutorial will use as an example a company website (example.local) that will have site areas and content for two groups :
finance department and planning department. The goal is to restrict editing of each department's area/content to members of that department. But also we need to restrict the visibility of some content only to department members, other content to general authenticated users in the company, while some content should be visible on the homepage of the company website.

1. Install Drupal

The process of Drupal installation is described very well in its INSTALL.txt.
This tutorial is written for Drupal 5.x version
Thus we are not going to go here into details. Make sure you have installed Drupal, created a database and you have successfully created the first user (username 'admin')

2. Install the taxonomy_access module

We need this module to achieve a fine-grained access policy for our departments. In the folder where you have you drupal files go to the sites/all folder and create a new folder "modules" here. Download (http://drupal.org/project/taxonomy_access) and extract the
taxonomy_access module in the newly created folder. This tutorial is based on the dev version, taxonomy_access-5.x-2.x-dev
(http://drupal.org/node/153216). This newer version introduces some important SQL optimizations, which drastically reduce the number of database records required for sites with a large number of terms and roles. The admin interface has been updated to allow you to keep your access rules lean and mean.

Login as your admin user and go to Administer > Site building > Modules. Tick taxonomy_access checkbox and click "Save configuration" button. That's it.

3. Categories

Next we are going to categorize the site with the taxonomy module. If you are not familiar with it, the taxonomy help page explains simple usage of it. Go to administer > content management > categories.

3.1 Groups

First we will define a vocabulary that will contain our groups (departments). Create a new vocabulary "Groups". On creating the new vocabulary make sure you select all content types you want to be categorised by terms in this vocabulary (e.g. Page, Stories) . Leave 'hierarchy' disabled for now. You can build your groups hierarchy later. Check the "Multiple select" checkbox - this allows nodes to be assigned to more than one group (required in cases where you want your content to be available to more than one group).

Then add new terms in your Groups vocabulary. First is our Finance department and second is the Planning department. That is it for groups. You can extend this vocabulary as you want.

3.2 Access

Now we are going to declare levels of access using another vocabulary. Create a new vocabulary and name it "Access". On creating this vocabulary make sure you have selected the same content types as you've done for the Groups vocabulary. Disable 'hierarchy'. Check the
"Required" check-box - this assures that every node must have at least one access level.
Add the following terms:

  1. Public - A node marked as "Public" will be visible for anyone in the world (anonymous users)
  2. Restricted - visible only for Authenticated users
  3. Private - only group members can see it

This vocabulary just declares our Access levels. Next we are going to define them and make it all work as each term indicates.

4. Create user roles - and users.

Before defining our access policy we should add one more component: Roles.

In this tutorial we allow an authenticated user to create stories. Edit the role "authenticated user" (administer > user management > access control) and give it these permissions: "access content", "create story content" , and "edit own story content".

"Groups As Roles": there must be a one-to-one relationship between the terms in our Groups vocabulary and corresponding roles. We need a role for each of our groups.

Go to administer > user management > roles and add two new roles:

  • "group - finance" - Assigning this role to a user we will make that user a member of Finance Group
  • "group - planning" - Assigning this role to a user we will make that user a member of Planning Group

These groups are just simple labels so far and we are not going to assign any permissions for them.
Don't forget about users. Create two new users in your system:

  • username: 'accountant' (choose your own password) - and make that user a member of the Finance group, by giving the user the "group - finance" role.
  • username: 'manager' - and make that user a member of the Planning group, by giving that user the "group - planning" role.

For testing purpose add one more user. This user should not be a member of any group: username: 'user'. Do not assign any role. All registered users have the authenticated role assigned by default.

Your User's list should look like this.

5. Set role access control with the taxonomy_access module

First read the module's documentation, that will help you to understand things better. (Administer > Help > Taxonomy Access Control)

Go to administer > user management > taxonomy access: permissions. You should see a list of roles registered in your system.

5.1 Permissions for anonymous user.

Rule: By default, an anonymous user must be denied access to any content which is not categorised as "Public".
Click on "edit" next to "anonymous user." There is a drop-down list box at the bottom just above the delete and save buttons. Select the "default" item under "Access".
Set View to Deny, and for Update and Delete, set Ignore. Untick the check boxes for Create and List.
Press the "Add" button and "Save All". Removing the ticks for Create and List mean that the user cannot create nor list any content categorized by the Access vocabulary.

This is the default access policy for an anonymous user. We just denied the user access to any categorised content. But we need to give the user permission to see content from the "Public" category. Thus, we need to define an exception to the above "default" rule.

Select "Access - Public" in the drop-down list. Set View to Allow, and for Update and Delete, set Ignore.
Untick the check boxes in Create and List. Press the "Add" button and "Save All". We have granted access to view "Public" content. You might set "List" checked, then your visitor will see a "Public" link in each node. But we removed it because visitors should not know about our access categories.

Your screen should look like this:

5.2 Permissions for authenticated user

Rule: All authenticated users are allowed to access, create and list "Public" and "Restricted" content, but not "Private" content, unless a user is member of a group. Users should know about all groups existence.

Next, go back to administer -> user management -> taxonomy access: permissions.
Click on "edit" next to "authenticated user". We must explicitly define grants for all access levels for this role, because all registered users have this role by default.

Select "Access - Private" in the drop-down list. Set View to Deny, and for Update and Delete, set Ignore. Untick the check boxes for Create and List. Press the "Add" button and "Save All".
Select "Access - Public" in the drop-down list. Set View to Allow, and for Update and Delete, set Ignore. Tick the check boxes for Create and List. Press the "Add" button and "Save All".
Select "Access - Restricted" in the drop-down list. Set View to Allow, and for Update and Delete, set Ignore. Tick the check boxes for Create and List. Press the "Add" button and "Save All".

And we must let our users to be aware about the existence of groups. Select "Groups - default" in the drop-down list. Set Ignore for View, Update and Delete. Tick the List check-box only, and untick the Create check-box. Press the "Add" button and "Save All".

Your screen should look like this:

5.3 Permissions for groups.

Rule: Group members must conform to the access policy defined by the "authenticated user" role. But additionally they must be able to access, create and list "Private" content assigned to a group of which they are a member.

A user cannot become a group member unless the user is a registered user of the site. Once a user registers and joins a group, the user receives permissions given to the "authenticated user" role and those given to the "group - NAME" role as well as grants (defined in taxonomy access) for each role.

Users with multiple user roles: Allow/Ignore/Deny options are interpreted only within one user role. When a user belongs to multiple user roles, then user gets access if ANY of his user roles has the access granted. In this case, permissions for the given user are calculated, so that the permissions of ALL of his user roles are "OR-ed" together. Meaning that Allow will take precedence over Deny.

First we define grants for the "Finance" role/group.

Go back to administer -> user management -> taxonomy access: permissions. Click on "enable" next to "group - finance".
Select "Access - Private" in the drop-down list. Set Ignore for View, Update and Delete. But tick the check boxes for Create and List. Press the "Add" button and "Save All".

But our rule requires that a user should not be allowed to create content in a group of which that user is not a member.
Therefore, select "Groups - default" in the drop-down list. Set Ignore for View, Update and Delete. Untick the check boxes for Create and List. Press the "Add" button and "Save All".

But a user must be able to access, create and list all content of his group.
Select "Groups - Finance" in the drop-down list. Set Allow for View and Ignore for Update and Delete. Tick the check boxes for Create and List. Press the "Add" button and "Save All".

If you want your group members to be able to edit content written by other members in the same group, you might set Allow to Update in that group. Or you might define a new role (group-finance-admin) for that and configure grants within that role. But here we keep it simple.

The result should look like this for your Finance group.

Repeat the whole process for the Planning Group. Go back to administer -> user management -> taxonomy access: permissions. Click on "enable" next to "group - planning". Use the "Planning" item under "Groups" in the drop-down list now.

After you have finished, the result for Planning should look like this.

Remember that you need to rebuild the node access permissions on existing pages before the changes you make will be effective. You can do this under "Post Settings"

6. Test

Let us now see how it works.
To make it easier to see how it all plays out, let us create a block with a list of our groups. Each item in that list will be a link to the content of the corresponding group.

Go to Administer > Site building > Blocks. Click on the "Add block" link. In the "Block description" field put "Groups". Then put the following PHP code inside the "Body" text-box:

<?php
$vid = 1;  //The vid is the vocabulary id of the Groups  we wish to list the terms from
$items = array();
$terms = taxonomy_get_tree($vid);
foreach ( $terms as $term ) {
$items[] = l($term->name, 'taxonomy/term/' . $term->tid);
}
if (count($items) ) {print theme('item_list', $items);}
?>;

Below "Body", expand "input format section" and select the "PHP code" option. Click the "Save" button.

Next define a region for this new block. Choose "left sidebar" and set the Weight to 1. Click "Save". Add a block title by clicking "configure" next to block. Put "Groups" in the Block title field. Save.

Your block should now look like this.

Log in as the "accountant" user. Click on the "Create content" link. Then create a story. Being logged in as the accountant user (member of Finance group) you can see only "Finance Group" in the Groups list box.
The accountant user cannot create any content in other groups.

Fill the Title text box, select Finance Group in Groups list-box, and make this a Public announcement by selecting Public (anonymous users) from the Access drop-down list. Write something in the Body text-box and submit it.

Log out and check if the anonymous user can see the new story.
Then, if you create another story and set Access to "Restricted" your public site visitors will not be able to access this story. Only registered users will be able to - including Our "manager" and "user".

Next try to create a private story.

In this case, neither "manager" (a member of another group) nor "user" (simple user) nor anyone (anonymous user) from the world can access the private story, only Finance group members.

Conclusion

It is important to remember that the "areas" you have created are really an abstract thing. A node is part of an area simply by virtue of its categorization.

Everything described here was fully tested. A database dump with the configuration described in this tutorial is available for download and import into your own database. (This configuration assumes you have put the taxonomy_access module in the ./sites/all/modules/ folder.)

Download database dump: http://drupal.org/files/gar_tutorial_db_dump_sql_tar.gz

We would be happy to answer your questions related to the approach described. But we also ask for your feedback on this approach,
whether it has advantages over others, or whether there are problems we have not realised.

Please also see our second tutorial http://drupal.org/node/201673 showing how to extend this approach to create a multisite installation.

Comments

kofiampaabeng’s picture

Thanks for the tutorial.
I'm pretty new to Drupal. I followed this tutorial and couldn't get the Groups to load. I get no error with the php code . Am I missing something?
I'm using Drupal 6.12.
Do I need to do anything special to access the api? The function taxonomy_get_tree($tid) returns an empty array.
I have however been able to use the groups and access created to control other pages.
Further insights will be helpful...
Thans

kofiampaabeng’s picture

Solved my own problem.
It's quite trivial actually.

radoeka’s picture

@kofiampaabeng

what did you solve and how did you do it? That might be usefull for others too!

carloscuzme’s picture

I have the same problem, can you kindly explain what you did? I shall be grateful as I am new to drupal.

Regards

MjrNuT’s picture

The php code for the block needs to be edited for:

$vid = 1 The number is associated with the Vocabulary added, in this case Groups. Mine was a value of 5, as I also had Forum Topic, Blogs, etc. vocabs.

Regarding the Block made for Groups, I am having a problem with correct visibility of the particular Group listing.

Eg. Family and Friend Groups. Desire to have Family to have more permissions that Friend. Have done this via User mangt>Permissions for those Roles.

In following this tutorial, I expect to have Family Group be able to see both Groups in the block. Conversely, when logged in as Friend Group, I still see link in Block for Family and can go to the page when clicking the link.

Can someone please explain my mistake?

Thanks in advance.

ps. My purpose of this is ability for authors of subject groups to set content types to particular group. Slight different from intended tutorial as my groups have Family upper level to Friend, which allows Family to see Friend content, but not in reverse. Is this still a good approach here?

det21’s picture

Thanks for the great tutorial :-)

But I got one more question....

I use i18n with taxonomy translation, which works fine with "normal" vocabularies.
But it seems to collide with the taxonomy access module on the groups and permissions vocabularies.

What multilingual setting would be the right one for the vocabularies used by taxonomy access?

(Taxonomy access permissions for the node translations shall be same the the original node)

Would be great if you could get me a hint.....

Thanks, Detlef

seregagorl’s picture

Hi,
It's a very nice solutions for my needs. just i wonder if it is proper for 1000 minisites managment?
thanks,
serge

FotoPilotas’s picture

Thanks for this information.

Can anybody write a script, that shows only term list from that vocabulary, witch permited to see to that user ? It would be usefull not only for me :)

Manna69247’s picture

Thank you for the detailed write-up. As a newbie it was my first touch on taxonomy and group permissions. I've learned allot and it works exactly how I need it to be for my site. THANX!

Todd Zebert’s picture

This is a great solution but the obvious limitation is that it does not handle the case of Users being in multiple departments/groups WITH different levels of access, or to look at another way, levels of access within a group.

Suppose User A is in group "planning" but he needs read-only access to "finance", even content marked as "private".

I don't see how this is possible without creating multiples of department Roles such as "Finance-guest" (R/O access), or "Finance-Admin" (able to edit other's post, for instance).

IT Sherpa: CTO, Founder, Full stack Dev, Drupal, Wordpress, more. Crushing on Angular, Node, JS & embedded C/C++.
Organizer for Drupal LA https://groups.drupal.org/la Meetup and 2016, 17, 18 LA Camps https://drupalcampla.com/

ashoktcr’s picture

Hi all,

Thanks for the information,
when i try to implement your instruction, at the sixth step

(6. Test)

, i couldn't put the code in PHP format, input format is filtered HTML and Full HTML. I am using drupal 6 version. Anyway i add the code, but the whole code is displayed in the left sidebar section. I don't understand how it's gets wrong.

Thanks in advance

tgraydon’s picture

You probably need to enable the PHP filter in Admin -> Site Building -> Modules, in the Core modules. Once that is enabled, go back into the settings for your content block and you should now see the PHP filter option. I ran into the same issue, and that fixed it for me.

Tracy

ashoktcr’s picture

Thanks tgraydon,

Now its OK.

choitz’s picture

I found this incredibly helpful after despairing for several days.
Now I just need to allocate users to groups automatically... but I'm fairly sure there's a module for that! I did this in D7, and there's little difference, also I don't have PHP snippets, but copied url from term (Home » Administration » Structure » Taxonomy »[Vocabulary] >Click [Term]) opened two tabs login user1 pasted url, second tab logged out then in with user2 and pasted url. While this is a great way to get your head around the whole concept, if you're happy to go down the module route, you may wish to look at this: http://drupal.org/project/role_vocabulary (although I've not tested it).

Cheers!

dewey’s picture

I am trying to set up a small town website. I would like the police department to be able to change police content including modifications to the police menu, the fire department to be able to make changes to fire content including the fire menu, etc.; but only allow departments to change their own content and menus but not be able to change other department content and menus.

I can find multiple ways to restrict who can change and create content, but I can't seem to find a way to control which groups can modify specific menus - i.e restrict the police department to only be able to modify the police menu, the fire department only be able to modify the fire menu.

Any guidance would be appreciated.