Plone 4 Development: Understanding Zope Security

Build robust, content-centric web applications with Plone 4.


Professional Plone 4 Development

Professional Plone 4 Development

Build robust, content-centric web applications with Plone 4.

        Read more about this book      

(For more resources on Plone, see here.)

Security primitives

Zope's security is declarative: views, actions, and attributes on content objects are declared to be protected by permissions. Zope takes care of verifying that the current user has the appropriate access rights for a resource. If not, an AccessControl.Unauthorized exception will be raised. This is caught by an error handler which will either redirect the user to a login screen or show an access denied error page.

Permissions are not granted to users directly. Instead, they are assigned to roles. Users can be given any number of roles, either site-wide, or in the context of a particular folder, in which case they are referred to as local roles. Global and local roles can also be assigned to groups, in which case all users in that group will have the particular role. (In fact, Zope considers users and groups largely interchangeable, and refers to them more generally as principals.) This makes security settings much more flexible than if they were assigned to individual users.

Users and groups

Users and groups are kept in user folders, which are found in the ZMI with the name acl_users. There is one user folder at the root of the Zope instance, typically containing only the default Zope-wide administrator that is created by our development buildout the first time it is run. There is also an acl_users folder inside Plone, which manages Plone's users and groups.

Plone employs the Pluggable Authentication Service (PAS), a particularly flexible kind of user folder. In PAS, users, groups, their roles, their properties, and other security-related policy are constructed using various interchangeable plugins. For example, an LDAP plugin could allow users to authenticate against an LDAP repository.

In day-to-day administration, users and groups are normally managed from Plone's Users and Groups control panel.


Plone relies on a large number of permissions to control various aspects of its functionality. Permissions can be viewed from the Security tab in the ZMI, which lets us assign permissions to roles at a particular object. Note that most permissions are set to Acquire—the default—meaning that they cascade down from the parent folder. Role assignments are additive when permissions are set to acquire.

Plone 4 Development: Understanding Zope Security

Sometimes, it is appropriate to change permission settings at the root of the Plone site (which can be done using the rolemap.xml GenericSetup import step—more on that follows), but managing permissions from the Security tab anywhere else is almost never a good idea. Keeping track of which security settings are made where in a complex site can be a nightmare.

Permissions are the most granular piece of the security puzzle, and can be seen as a consequence of a user's roles in a particular context. Security-aware code should almost always check permissions, rather than roles, because roles can change depending on the current folder and security policy of the site, or even based on an external source such as an LDAP or Active Directory repository.

Permissions can be logically divided into three main categories:

  • Those that relate to basic content operations, such as View and Modify portal content. These are used by almost all content types, and defined as constants in the module Products.CMFCore.permissions. Core permissions are normally managed by workflow.
  • Those that control the creation of particular types of content, such as ATContentTypes: Add Image. These are usually set at the Plone site root to apply to the whole site, but they may be managed by workflow on folders.
  • Those that control site-wide policy. For example, the Portlets: Manage portlets permission is usually given to the Manager and Site Administrator roles, because this is typically an operation that only the site's administrator will need to perform. These permissions are usually set at the site root and acquired everywhere else. Occasionally, it may be appropriate to change them here. For example, the Add portal member permission controls whether anonymous users can add themselves (that is, "join" the site) or not. Note that there is a control panel setting for this, under Security in Site Setup.

Developers can create new permissions when necessary, although they are encouraged to reuse the ones in Products.CMFCore.permissions if possible.

The most commonly used permissions are:



Zope Toolkit name


Access contents information

AccessContents Information

zope2.AccessContents Information

Low-level Zope permission controlling access to objects




Access to the main view of a content object

List folder contents



Ability to view folder listings

Modify portal content



Edit operations on content

Change portal events



Modification of the Event content type (largely a historical accident)

Manage portal



Operations typically restricted to the Manager role.

Request review



Ability to submit content for review in many workflows.

Review portal content



Ability to approve or reject items submitted for review in many workflows.

Add portal content



add new content in a folder. Note that most content types have their own "add" permissions. In this case, both this permission and the type-specific permission are required.

The Constant column in the preceding table refers to constants defined in Products. CMFCore.permissions. The Zope Toolkit name column lists the equivalent names found in ZCML files in packages such as Products.CMFCore, Products.Five and (at least from Zope 2.13), AccessControl. They contain directives such as:


This is how permissions are defined in the Zope Toolkit. Custom permissions can also be created in this way. Sometimes, we will use ZCML directives which expect a permission attribute, such as:


The permission attribute here must be a Zope Toolkit permission ID. The title of the <permission /> directive is used to map the Zope 2-style permissions (which are really just strings) to Zope Toolkit permission IDs.

To declare that a particular view or other resource defined in ZCML should not be subject to security checks, we can use the special permission zope.Public.

        Read more about this book      

(For more resources on Plone, see here.)


Roles can be assigned globally to users and/or groups from the Users and Groups control panel. It is usually easier to create logical groups that can be assigned a set of roles once, rather than manage those roles for each user. The default Administrators and Reviewers groups have the Manager and Reviewer roles, respectively. There is also a pseudo-group called Logged-in users, which can be used to manage global and local roles that should apply to everybody who logs into the site. Every user is automatically a member of this group.

The Sharing tab, which appears on most content items, can be used to search for users or groups and assign them local roles. Note that the set of roles on the sharing tab is limited to those explicitly white-listed.

The sharing.xml GenericSetup import step can be used to list additional local roles on the sharing tab. See for more details.

There are seven main roles in a default Plone installation.




This is the default role for a Plone user. Quite a few permissions that normally apply to logged in users are given to this role. In CMF and Plone, the term member is also used more generally to describe users who are managed inside the site (as opposed to Zope-wide users).



This is the super-user role. Members of the Administrators group will have this role. Use it sparingly: a user with Manager rights has almost unlimited power over a Plone site.

Site Administrator

This role, which was introduced with Plone 4.1, allows us to define users with the ability to change the settings in Plone's control panels and view and edit almost all content, without giving them access to potentially destructive actions in the Zope Management Interface.


Users with this role, which is granted to the Reviewers group, can view and approve content that has been submitted for review.


This role is intended to be used as a local role only. It can be assigned from the Sharing tab, where it appears as Can view. When granted the Reader role, a user will usually be allowed to view a content object, even when normal Members cannot, for example, because the object is private.


This is the counterpart to Reader, is it used to assign modification rights locally. It is called Can edit on the Sharing tab. This allows content owners to delegate edit rights selectively to other users.


This is used to delegate the right to add content items in folders. It appears on the Sharing tab under the title Can add.

If you create a new content type with a custom "add" permission, you should normally grant this to the Contributor role globally, using rolemap.xml. Similarly, if you have any custom permissions necessary to view an object, they should normally be granted to the Reader role, whilst any permissions necessary to modify an object should be granted to the Editor role.

In addition, Zope defines three automatically assigned roles:




This role is given to the owner of the current content item. Normally, this is the user who created it.


This is given to all logged-in users. This is more low-level than the Member role and cannot be revoked or granted explicitly. Therefore, it is usually better to rely on the Member role when designing a permission scheme for logged-in users.


This role refers to non-logged in users. There is a special user object, also called Anonymous, which is always granted this role.

Wherever a permission is granted to Anonymous, Zope will in effect stop checking the permission. This means that it is not possible to assign a permission to non-logged in users without also granting it to all authenticated users.

It is possible to create new roles through the rolemap.xml import handler in a GenericSetup profile (or through the Security tab in the ZMI).

Think carefully before adding too many new roles. A large number of custom roles is normally a sign that the security policy is not well thought-through. New roles usually require changes to the site's workflows.

Manipulating permissions and roles programmatically

To validate a permission in a particular context, such as the current content object, for the current user, we can do:

from AccessControl import getSecurityManager
from Products.CMFCore.permissions import ModifyPortalContent

sm = getSecurityManager()
if sm.checkPermission(ModifyPortalContent, context):
# do something

Permissions are identified by strings, so we could use "Modify portal content" instead of importing and using ModifyPortalContent, but using the constant is less error-prone.

To grant a particular permission to a list of roles, we can do:

context.manage_permission("Portlets: Manage portlets",
roles=['Manager', 'Site Administrator', 'Owner'], acquire=1)

Of course, it would be better to use a constant (provided there is one defined), but as the example shows, strings work too. Set acquire=0 to turn off acquisition of role assignments.

To find out if the current user is logged in (that is, whether the user is "anonymous" or not), we can use the portal_membership tool:

from Products.CMFCore.utils import getToolByName

mtool = getToolByName(context, 'portal_membership')
if mtool.isAnonymousUser():
# do something

Similarly, we can obtain the current member from this tool:

member = mtool.getAuthenticatedMember()
if member is not None:
userId = member.getId()

The user ID is a string that uniquely identifies the user. It should not be confused with the user's login name, which is the name used in combination with a password to log into the site. Sometimes, the user ID and login name are the same, but this is not always the case, particularly when authenticating against external user sources such as LDAP or Active Directory repositories.

Once we have a member object, we can look up member properties as in the following code:

fullName = member.getProperty('fullname')
email = member.getProperty('email')

Member properties are enumerated on the Properties tab of the portal_memberdata tool.

We can also find members by ID, using the following line of code:

adminUser = mtool.getMemberById('admin')

Take a look at the Doc tab of the portal_membership tool in the ZMI, or see Products.CMFCore.MembershipTool for more information about its API.


In this article, we have taken a look at Plone's approach to security, including key concepts such as users, groups, roles, and permissions.

Further resources related to this subject:

Books to Consider

Practical Plone 3: A Beginner's Guide to Building Powerful Websites
$ 19.50
Professional Plone 4 Development
$ 35.99
comments powered by Disqus