Security and Workflow

Security and Workflow
Security should never be an afterthought, particularly when building web applications. Luckily, Zope and Plone provide a robust and flexible security model that lets you concentrate on building your application instead of worrying too much about how to lock it down. That is, so long as you understand a few basics.
In this chapter, we will explain the building blocks of Zope security—users, roles, and permissions—as well as workflows, the usual way to manage permissions in Plone. As a demonstration, we will build a custom workflow for the Optilux website and add it to the policy product we created in the previous chapter.
Security Primitives
Zope's security is declarative. Views, actions, and attributes on content objects are protected by permissions and Zope takes care of verifying that the current user has the appropriate access rights. If not, an AccessControl.Unauthorized exception will be raised.
Permissions are not given directly to users. Instead, permissions are assigned to roles. Users can be given any number of roles, either globally in the portal, or in the context of a particular folder. Global and local roles can also be assigned to groups, in which case all users in that group will have the particular role. This makes security settings much more manageable than if they were assigned to individual users.
Users and Groups
Users and groups are kept in a user folder, called acl_users. There is one at the root of the Zope instance, typically containing only the default Zope-wide administrator. There is also an acl_users folder inside Plone, which manages Plone's users
and groups.

Since version 2.5, Plone has used the Pluggable Authentication Service (PAS), a particularly flexible kind of user folder. In PAS, users, groups, their roles, and their properties are constructed using various interchangeable plug-ins. For example, an LDAP plug-in could allow users to be found in an LDAP repository. We will revisit PAS in Chapter 13, when we look at more advanced member management, and again in Chapter 18, when we configure LDAP authentication.
You can manage users and groups from acl_users in the ZMI, but the user interface here can be a little confusing. A much better place to create users and groups is Plone's Users and Groups control panel, under Site Setup.
Permissions
Plone relies on a large number of permissions to control various aspects of its functionality. To see for yourself, go into the ZMI and click the Security tab at the root of the Plone site. This tab lets you assign permissions to roles at a particular object. Note that for most permissions, the Acquire permission settings checkbox is checked, meaning that permissions cascade down from the parent. Role assignments are additive when permissions are set to acquire.

Sometimes, it is appropriate to change permission settings at the root of the site, 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 the particular context.
Security-aware code should almost always check for permissions, rather than roles. Checking for specific user or group names is rarely a good idea, because roles can change depending on the current context and security policy of the site.
[backcolor=#f7f7f7]Permissions come in three main flavors:
Permissions 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 Products.CMFCore.permissions. Core permissions are normally managed by workflow.
Permissions that control the creation of particular types of content objects, such as ATContentTypes: Add Image. These may be set at the portal root to apply to the whole portal, or they may be managed by folder-level workflow.
Permissions for site-wide policy. For example, the Portlets: Manage portlets permission is given to the Manager role, because this is a manager-only operation. These permissions are usually set at the portal root and acquired everywhere else. Occasionally, it may be appropriate to change them at the site root. For example, the Add portal member permission controls whether anonymous users can add themselves (i.e. join the site). In Plone 3, however, 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 re-use the ones in Products.CMFCore.permissions if at all possible. We will see examples of declaring new permissions (controlling the ability to add content of various types) when we create custom content types in Chapter 10, and again in Chapter 12.[/backcolor]
The most commonly used permissions are:
Permission
Constant
Zope 3-style name
Controls
Access contents information
AccessContents-Information
zope2.AccessContents-Information
Low-level Zope permission controlling access to objects.
View
View
zope2.View
Access to the main view of a content object.
List folder contents
ListFolderContents
cmf.ListFolderContents
Ability to view folder listings.
Modify portal content
ModifyPortalContent
cmf.ModifyPortalContent
Edit operations on content.
Manage portal
ManagePortal
cmf.ManagePortal
Operations typically restricted to the Manager role.
Add portal content
AddPortalContent
cmf.AddPortalContent
Ability to add new content in a folder. Note that many content types have their own "add" permissions. In this case, both this permission and the type-specific permission are required.
The Constant column refers to constants defined in Products.CMFCore.permissions. The Zope 3-style name column lists the equivalent names found in Products.Five's permissions.zcml, which contains directives such as:

<permission
id="zope2.View"
title="View"
/>
This is how new permissions are defined in pure Zope 3. Sometimes, we will use ZCML directives, which expect a permission attribute, such as:
<browser:page
name="some-view"
class=".someview.SomeView"
for="*"
permission="zope2.View"
/>
The permission here must be a Zope 3 permission id. In Zope 2 with Five, the title of the <permission /> directive is used to map Zope 2 permissions (which are really just strings) to Zope 3 permissions. In fact, permissions in Zope 3 are named utilities providing IPermission, but you don't need to worry about that.
Roles
Roles can be assigned 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 to manage those roles for each and every user. The Administrators and Reviewers groups that are created by default have the Manager and Reviewer roles, respectively.
Local role assignment is usually managed via the Sharing tab that appears on most content items. You can search for a user or group to assign local roles. Note that the set of roles on the sharing tab is limited to those explicitly white-listed.
See the plone.app.workflow module, in particular the localroles.py file and the related entries in configure.zcml. You can use similar declarations in your own product to make more roles available through the sharing tab.
Other local roles can be granted from the Security tab in the ZMI. However, you should only do this if absolutely necessary. Again, workflow is normally a more appropriate way of managing local security assignments.
There are six key roles in a default Plone installation.
Member is the default role for a portal user. Quite a few permissions that normally apply to logged in uses are given to this role, so it makes sense to re-use it where possible.
Manager is the super-user role. Members of the Administrators group will have this role.
Reviewer, granted to the Reviewers group, allow users to view and approve content that has been submitted for review.
Reader is intended to be used as a local role only. It can be assigned from the Sharing tab. When granted the Reader role, a user will (almost) always be allowed to view the content object, even when normal Members cannot.
Editor, the counterpart to Reader, is used to assign modification rights locally. This allows content owners to delegate edit permissions selectively to
other users.
Contributor is used to delegate permission 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. Similarly, if you have any custom permissions necessary to view an object, they should normally be granted to the Reader role, while any permissions necessary to modify an object should be granted to the Editor role.
In addition, Zope defines three automatically assigned roles:
Owner is given to the owner of the current content item. Normally, this is the user who created it.
Authenticated 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.
Anonymous refers to non-logged in users. There is a special user object, also called Anonymous, which is always granted this role.
In addition, there is a pseudo-group called Logged-in users, which automatically includes all authenticated users. This appears on the Sharing tab to allow the site administrators to assign local roles to all logged-in members. For example, you could give the Contributor role to this pseudo-group in the default News folder to allow any user to create new news items in that folder and submit them for review.
It is possible to create new roles, either through a rolemap.xml import handler in a GenericSetup profile, or through the Security tab in the ZMI. Think carefully before doing so, however. A large number of custom roles is normally a sign that the security policy is not well thought-through. When adding roles, it is usually necessary to amend the site's workflows to incorporate them.
Manipulating Permissions and Roles Programmatically
Most low-level security operations are provided by the AccessControl.Role.RoleManager mix-in class, which is included in all content objects, including the Plone Site object itself. Take a look at it on the Doc tab (assuming you have the DocFinderTab installed):
To validate a permission in a particular context—such as the current content object—for the current user, you 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 you could write "Modify portal content" instead of importing and using ModifyPortalContent, but using the constant makes it less likely that you will make a mistake.
To grant a particular permission to a list of roles, you can use:
context.manage_permission("Portlets: Manage portlets",
roles=['Manager', '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 or not (i.e. whether the user is anonymous), you can use the portal_membership tool:
from Products.CMFCore.utils import getToolByName
mtool = getToolByName(context, 'portal_membership')
if mtool.isAnonymousUser():
# do something
Similarly, you can obtain the current member from this tool:

member = mtool.getAuthenticatedMember()
user_id = member.getId()
You can also find members by ID using:
admin_user = 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.







设置