ZopeMag's mascot the ZOPE fish


Article Finder
People
Issue 8 - Revision 8  /   September 26, 2004 


 
  ZopeMag Links:
Latest Issue
About the Fish
Issue 10
Issue 09
Issue 08
Issue 07
Issue 06
Issue 05
Issue 04
Issue 03
Issue 02
Issue 01
 
 
Downloads
     
  Letter from the Editor:
   Issue 8

Interviews:
Each issue we interview important people in the Zope world.

  Stéfane Fermigier

Articles:
Throughout the quarter we cover topics of interest to Zope developers, designers, and users.

  Fine Grained Permissions

  Archetypes Part III

  Intro to Silva

  Profiling Zope

  Intro to CPS

Product Review:
Too many Products, too little time? ZopeMag keeps you up-to-date which Zope Products are worthwhile checking out.

  DocFinderTab
  mxODBC DA


Guides:
This quarter we bring you a new SuperGuide. Our miniGuides and SuperGuides give you the background knowledge you need to mastering Zope.

  miniGuide to Zope Hosting
  SuperGuide - Zope for Newbies (Part II)
 
 
Downloads
     
  URLs / Download
Products we talk about in this issues Articles and Reviews

     

Illustration by Lia Avant
tutorial
Fine Grained Permissions

Fine Grained Permissions
- Step-by-Step
- - - - - - - - - - - -

By Chris Curvey  | May 27, 2004

print

Introduction

A fully configured Plone instance comes with a thoroughly functional and quite useful workflow. Content is always in one of four states: “private” (where only members of the site can see it), “visible” (where anyone who knows how to find it can see it), “pending” (which is just like “visible”, except the content shows up as awaiting approval), and “published” (where anonymous users, i.e. anyone, can see it). This is fine for many applications, yet many companies make their money by selling the information on their site (for example, ZopeMag). What you really want here is the ability to “publish to members of a group, and ONLY to those members.” Plone doesn't offer this out-of-the-box .This article will walk you through the steps needed to make it work.

The Problem

The customer is a small business association with very little technical experience. The owners make their living by providing information and services to the members of the association. Some of the information on their site is promotional in nature, and needs to be available to the general public. That's easy to handle with the standard Plone workflow.

In order to entice people to become dues-paying members of the association, it publishes some “premium” content that is only available to dues-paying members. (Non-members can see the link, but are encouraged to become members when they click on the link.) Premium content can appear anywhere throughout the site. Note: In order to avoid confusion between the Plone concept of a “member” and the business concept of a member, we will refer to the dues-paying users as “subscribers.”

In addition to having subscribers, the association has about 30 Special Interest Groups (SIGs). Each SIG has rules about who can join, and joining a SIG also requires an extra payment to the association. Each SIG has its own folder, which can contain either public content or SIG-only content, i.e. content available only to members of that SIG, but all SIG-only content is placed in that folder.

The association also offers courses to the public. The instructors are usually not employees of the association, but are independent contractors. The association would like to set up a section of the site for each course where the instructor could post assignments and respond to student questions.

Play Along at Home!

This article is written as a tutorial, so you will want to have a Plonesite that you can play with while reading. I suggest that you set up a brand new Plonesite in order to minimize any complications that might arise from an existing site. DO NOT use a production site, since we will be modifying the default workflow.

Handling Premium Content

The first problem that we have is that the existing “states” within Plone don't offer us the ability to publish to a limited subset of users. If content is “private,” then it's only available to the author. If content is “visible”, then it's visible to anyone who knows the corresponding URL. It might be tempting to try to use this “security through obscurity” to protect your content, but this won't work for our small business association, since it may need to revoke permissions from a user for non-payment of dues. (If an ex-member of our association user-bookmarked an item, and it's still “visible”, the ex-member will still be able to see the content.)

So the first thing to do is add a new “state” to our system. Using the ZMI:

  1. Using the left-hand navigation of the ZMI, go to portal_workflow->plone_workflow->states. Add a new state called PREMIUM.
  2. Go to portal_workflow
  3. Go into the PREMIUM state and add the “reject” and “retract” transitions (same as PUBLISHED).
  4. Go to the “transitions” area of the workflow (using the left-hand navigation) and add a new transition called “makepremium.” Give it a destination state of "premium"; the guard should be "Review portal content"; name (formatted) should be "Make Premium".
  5. Go back to the list of states and add “Make Premium” to each state that currently has “publish” as an available transition.
  6. Go to the root of your Plonesite, go to the “security” tab, and add a role called “subscriber”
  7. Go back to workflow->states->premium, and for the “View” and “Access contents information” permissions, uncheck “Acquire”, then give these permissions to Manager, Owner, Reviewer, and Subscriber.

    (If you aren't sure why you're doing these things, don't worry. An explanation will be coming shortly.)

    Now go to the Plone interface.

  8. Go to “plone setup”->”users and groups”. Click on the “groups” tab. Add a group called “subscribers”. (Note that the Plone group is “subscribers” and the Zope role is “subscriber”).
  9. Add a user to the Plonesite (I called the user "suser", for “subscriber user”), and make him/her a member of the "subscribers" group. (Click on "suser", then use the "groups membership" tab.)

    Go back to the ZMI interface

  10. Click on the "acl_users" folder, then on the "groups" tab. Click into the “subscribers” group, and check the "subscriber" role. Hit the "change" button.
  11. Go to the root of your Plonesite, then to the "security" tab. For "Access contents information" uncheck "acquire", then check "Anonymous". (Note: this seems to break the default Plone behavior of showing the contents of a folder if there's no index page, but that may very well be intentional.)

Now try it out. In the root folder of your Plonesite, create a document called "ordinary" (using the Plone interface) and publish it. Create another document called "superduper" and make it a premium document.

Using another browser (or after closing and reopening your browser):

Using another browser (or after closing and reopening your browser):

  1. Try to hit the root of your Plonesite (just to make sure nothing is horribly wrong). That should work.
  2. Try to hit the 'ordinary' document (http://localhost:8080/mytestplonesite/ordinary). That should also work.
  3. Try to hit the 'superduper' document (http://localhost:8080/mytestplonesite/superduper). You should get a login screen.
  4. Log in. You should see the “superduper” page.
What's Going On Here?

This is the theory behind what we just did. If you're in a hurry, feel free to skip down to “Handling the SIGs” for another walkthrough. But here's a short version:

  • Roles are a collection of permissions (the columns in the “security” page)
  • States contain a relevant subset of roles.
  • Groups are a collection of users
  • Groups are tied to roles

So at runtime, a user is in a group, which is associated with some roles, which are themselves collections of permissions.

States

The key to all this is the Plone concept of a “state”. While states do many things:, the important thing for this example is that they contain a template for permissions. That's what we're changing when we go to the “permissions” tab for our “premium” state. So if you look at that permissions tab (remember, you see it through the ZMI by going to plone_workflow->states->premium->permissions), you realize that the nice folks at Plone have cut down the huge list of permissions available through the ZMI “security” tab to a manageable list. For non-folderish things (like documents), you only care about:

  • Access Contents Information -- whether or not a user can see information *about* a document. For example, the owner and last modification date.
  • View -- whether or not a user can see the contents of the document.
  • Modify Portal Content -- whether or not a user can modify the contents of the document.

The workflow for folders is similar, and found in the folder_workflow. For folders, you care about the above three permissions, plus:

  • List Folder Contents -- whether or not a user can see what's in the folder.
Roles

“Role” is a Zope concept: it is actually just a collection of permissions. If you look at the list of roles in Zope (across the top on any of the “security” pages), you will see:

  • Anonymous -- any user who is using the site and has not logged in. (Supplied by Zope)
  • Authenticated -- any user who is logged in to the site. (Supplied by Zope)
  • Manager -- any user who is logged in and has the manager role. Managers do system-administrator types of things, like adding users and products, backing up the system, and configuring the system. (Supplied by Zope)
  • Member -- any user who is logged in and has the member role. Members have the ability to create content in their own folders (and elsewhere, if a Manager has given them permission). (Supplied by Plone)
  • Owner -- any user who is logged in and owns the piece of content being looked at. Owners can create, modify and delete the content that they own. (Supplied by Zope)
  • Reviewer -- any user who is logged in and has the reviewer role. When a member submits content for approval, it shows up in the reviewer's worklist. The reviewer can then reject the content or edit and then publish it. (Supplied by Plone)
  • Subscriber – any user in the current example who we have defined as being a subscriber. (Supplied by us.)

Note that any user who has any role beyond “Anonymous” implicitly gets all the permissions granted to the “Authenticated” role by means of acquisition. (Because you have to be authenticated for the system to know that you have another role.) As a general rule, you should not grant “modify portal content” permissions to the “Authenticated” role, because that would allow any authenticated user (i.e., any logged-in user) to modify content, regardless of their other roles.

The other dimension of acquisition comes from the "Acquire Permission Settings" checkbox. If this is checked, then any permissions from the folder that contains the object automatically apply to the object.

Handling the SIGs

If you've gotten this far, you're probably asking yourself, “Why on earth do I have to go through 11 steps just to limit content to a subset of the public? That's crazy.” And the answer is: this is a complicated problem. Security in Zope (and therefore in Plone) is very fine-grained. It gives you a lot of control, but it can be a pain to set up. On the other hand, once it's done, it's done.

Let us recall the issue with SIGs. A user can be a subscriber, and belong to zero, one, or more SIGs. That sounds like a permissions problem, doesn't it? Further, when you think “permissions,” you need to think “roles” and “states”. So now you need to go back and add a new state – which we will call “sig” - a corresponding transition called “makesig”, and a role called “sigMember”. (Think of this as an exercise.) add a group called “sigMembers” (via Plone) and then associate “sigMembers” with “sigMember” via the ZMI.

Remember: when you are setting up the permissions template for the “sig” state, don't assign permissions to “subscriber,” assign them to “sigMember”.

Now back to the Plone interface.

  1. Log in to your Plonesite as 'Manager'.
  2. Create a new folder in the home of your Plonesite called “Special Interest Groups”. Within that folder, create two more folders, called “animal” and “vegetable”.
  3. Go to the “plone setup” area, then to “user and group” administration.
  4. Create two new users: “andy” (who will belong to the animal SIG group) and “vera” (who will belong to the vegetable SIG group).
  5. Create two new groups: “animalSIG” and “vegetableSIG”.
  6. Go back to the “user” page and put “andy” in the “animalSIG” group. Put “vera” in the “vegetableSIG” group. (Once you click on a user, you have to click on the “group membership” tab to manage the groups. Note: as of Plone 2.0, there is a bug (2821) in Plone which prevents the user from showing up in the group immediately. If you set up “andy” in the “animalSIG” group, then put “vera” in the “vegetableSIG” group .If you go back to see “andy's” page, you should now see his group membership. If you don't, don't panic, it's probably been set up OK and will appear in a few minutes.
  7. Go to the “animal” folder and click on the “sharing” tab. Scroll down to the bottom of the page to where it says “Add Sharing Permission to Groups.” Check the “animalSIG” box, and select “sigMember” as the “role to assign.” Then click the button “assign local role to selected groups.”
  8. Then go to the “vegetable” folder and carry out the corresponding procedure for vera: Click on the “sharing” tab. Scroll down to the bottom of the page to where it says “Add Sharing Permission to Groups.” Check the “vegetableSIG” box, and select “sigMember” as the “role to assign.” Then click the button “assign local role to selected groups.”

Now it's time to try this out. As “Manager”, go into the animal folder and create a document called “tiger”. Change its state to “sig”. Go into the vegetable folder and add a document called “carrot”. change its state to “sig” as well.

Next, log out of the “manager” account and log in as “andy”. Go to the animal folder and click on “tiger”. You should be able to see the document. While still logged in as “andy”, go to the “vegetable” folder. You shouldn't be able to see anything, since “andy' doesn't have viewing rights in the vegetable folder. If you try to fake out the system by going directly to the “carrot” document (http://localhost:8080/myplonesite/vegetable/carrot), you should get an “insufficient privileges” report.

Try the corresponding things now after logging in as “vera”. Did you get what you expected?

What's Going on Here, II?

The only new concept that we've used here is “local role.” A “local role” permits you to give all the permissions of a role to a user within a specified folder. Within our “animal” folder, any member of animalSig (such as Andy) is treated as having the SIG role, and is able to read the content. Anyone who is not a member of animalSig (such as Vera) is just an ordinary member, and isn't allowed to read the content. Because we have different folders, we can create different local roles inside each one, so we don't have to create a different role for each SIG. The added bonus is that non-technical folks can manage this through the Plone interface, which is a lot less daunting (and a lot safer) than giving them access to the ZMI.

One question you might ask at this point is, “Instead of adding the 'sigMember' role, couldn't we have just created a local role for 'subscriber'?” The answer is, “not in this case.” Remember that we have two different levels of permissions – subscriber and SIG member. If we hadn't created the “sigMember” role, we couldn't prevent a subscriber from seeing all the information for all the SIGs. This we don't want to do, as the SIG members pay for the privilege of having access to a SIG.

Adding a Collaborative “Coursework” Area

The last problem we're going to try to solve is that of setting up special areas for courses. There are two things to remember. First, the course instructor needs to be able to create and manage documents (syllabus, assignments, course notes) within the folder for his course. Second, we want a way for students to be able to ask and answer questions. One note about this section: I've intentionally included some “false paths” in this section – not to confuse you, but to help you recognize common mistakes and how to correct them.

Let's start by creating a new folder at the root level called “courses.” Inside the “courses” folder, add two more folders, “basketweaving” and “pottery”. Publish all three folders.

We're going to add a new member, “Bob,” to the site. Bob is going to be our basket weaving instructor. Go to the “basket weaving” folder, and click on the “sharing” tab. Halfway down the page, you can search for an individual user: search for Bob.

Now we have a choice of what role Bob should play within the basket weaving folder.

  • Manager – this would give Bob complete control within the Basket Weaving folder.
  • Member – this would give Bob the ability to create content within the Basket Weaving folder and submit it for publication.
  • Reviewer – this would give Bob the ability to create and publish content within the Basket Weaving folder – including the ability to publish just to a local SIG.
  • Owner – this would give Bob permissions to create and delete content within the local folder.
  • SIG – gives Bob permissions to see content published to the SIG.
  • Subscriber – gives Bob permissions to see “premium” content.

For the purposes of this tutorial, we're going to treat a group of students enrolled in a class as just another SIG. So we want Bob to be able to create content within the folder and publish it to users who have the SIG role within the folder. Assign Bob the “Reviewer” and “Owner” roles (you'll have to go through the process once for each role), and let's try it out.

Log in to your Plonesite as Bob, and go to the Basket Weaving folder. Create a document. Publish it to the SIG. And watch the document disappear! What happened? Well, Bob has the right to publish to the SIG, but he is not a member of the SIG, which means he doesn't have the right (“permission”) to view content in the SIG. So the solution is to go back to the “sharing” tab, find Bob again, and add the “sigMember” role to Bob.

Now it's time to create students in the class. We want students to have the “Member” role within the folder (so that they can create and submit content), and the “sigMember” role so that they can see content. But constantly having to go back and add both roles to each student is going to drive us crazy, especially if we have a lot of students. The solution is to create a new group.

Using the Plone interface as “Manager”, go to the “plone setup” section, then to “user and group administration”. Create a new group called “students”, and give it “Member” and “sigMember” roles. Now add a user called “sam” and add him to the “students” group. Log in as Sam, and try to see what's in the “Basket Weaving” folder. You should be able to see it. Try to add a document. You should be able to add and submit it (but not to publish it). Log out as Sam and log in as Bob. The document that Sam created should be in your (Bob's) review list. This means that Bob can edit the document, adding his responses, and then publish the document to the SIG. (In reality, you would create a Discussion Board within your site and grant permissions to that, but product installation is beyond the scope of this article.)

Two notes about this example. The first is that because we gave Bob the “Reviewer” role, Bob has the right to publish content to the public, or even publish “premium” content. In reality, you may not want to give Bob all these permissions (then again, you might). If you wanted to limit Bob so that he can only publish to the SIG, you can do it, but that's a more advanced topic, dealing with transitions and permissions.

The second note is that if you have a lot of courses, you might want to create an “instructor” group and use that for assigning permissions to your instructors.

Troubleshooting

When you're working with states, you're eventually going to get things “not quite right”. Some permission will be set wrong, and you may end up going into the ZMI to manually change permissions until you figure out the right combination of permissions. When this happens, there's a useful little button that will clean up any changes you might have made during your experiments and put you back in a “known” state. If you go to the ZMI, then to portal_workflow for your Plonesite, and scroll down to the bottom of the page, there's a button marked “Update security settings.” What this will do is go through every workflow-aware object in your Plonesite and re-set the permissions as defined for each state.

If you get confused about the roles within a site, go look at the states in the workflow.


Chris Curvey


shim
shim  ZopeMag is committed to bringing you the best in Zope Documentation. shim
shim


Home   Subscribe   FAQ   Contact   Write for us   Privacy Policy   Weekly News   PyZine   opensourcexperts.com  

Reproduction of material from any of ZopeMag's pages without prior written permission is strictly prohibited. Copyright 2003 - 2005 ZopeMag Zope/Plone hosting by Nidelven IT