Local roles¶
Description
Creating and setting local roles of Plone members programmatically.
Introduction¶
Local roles allows user accounts to have special privileges for a folder and its children.
By default Plone has roles like
Contributor
,
Reader
,
Editor
, etc. and you can view these on the
Sharing tab and in
ZMI
Security tab.
Good introduction to roles: Basic Roles and Permissions in Plone
Creating a new role¶
New Plone roles can be created through the GenericSetup rolemap.xml file.
Example
profiles/default/rolemap.xml
<?xml version="1.0"?>
<rolemap>
<roles>
<role name="National Coordinator"/>
<role name="Sits Manager"/>
</roles>
<permissions>
</permissions>
</rolemap>
Adding a role to the Sharing Tab¶
To let the newly created role appear in the @@sharing tab, create a GenericSetup sharing.xml file.
Example
profiles/default/sharing.xml
<sharing xmlns:i18n="http://xml.zope.org/namespaces/i18n"
i18n:domain="plone">
<role
id="Sits Coordinator"
title="Is a sits coordinator"
permission="Manage portal"
i18n:attributes="title"
/>
</sharing>
The title is the name to be shown on the sharing page. The required_permission is optional. If given, the user must have this permission to be allowed to manage the particular role.
Note
For Plone 3, there is the collective.sharingroles addon. Since Plone 4, this is merged into plone.app.workflow.
Setting local role¶
manage_setLocalRoles
is defined in
AccessControl.Role.RoleManager.
Example:
context.manage_setLocalRoles(userid, ["Local roles as a list"])
Getting local roles¶
The
get_local_roles()
method returns currently-set local roles. This does not
return all the effective roles (which may include
roles acquired from the parent hierarchy).
get_local_roles_for_userid()
returns roles for a particular user as a tuple.
Example:
# get_local_roles() return sequence like ( ("userid1", ("rolename1", "rolename2")), ("userid2", ("rolename1") )
roles = context.get_local_roles()
Deleting local roles¶
manage_delLocalRoles(userids)
takes a list of usernames as argument. All local
roles for these users will be cleared.
The following example (membrane
-specific) will reset local roles based on external input
def _updateLocalRoles(self):
""" Resets Local Coordinator roles for associated users.
Reads Archetypes field which is a ReferenceField to membrane users.
Based on this field values users are granted local roles on this object.
"""
# Build list of associated usernames
usernames = []
# Set roles for newly given users
for member in self.getExtraLocalCoordinators():
# We are only interested in this particular custom membrane user type
if member.getUserType() == "local_coordinator":
username = member.getUserName()
usernames.append(username)
self.manage_setLocalRoles(username, ["Local Coordinator"])
membrane = getToolByName(self, "membrane_tool")
# Make sure that users which do not appear in extraLocalCoordinators
# will have their roles cleared
for username, roles in self.get_local_roles():
sits_user = membrane.getUserAuthProvider(username)
if not username in usernames:
print "Clearing:" + username
self.manage_delLocalRoles([username])
Blocking local roles¶
Local roles may need to be blocked on a particular object by default. This can be achieved by add a flag to your content object, like so:
class MyType(content.Container):
"""My content type
"""
implements(IMyType)
__ac_local_roles_block__ = True
Local role caching¶
Resolving effective local roles is a cumbersome operation, so the result is cached.
Warning
Unit testers: Local roles are cached per request. You need to clear this cache after modifying an object's local roles or switching user if you want to get proper readings.
Unit test example method:
def clearLocalRolesCache(self):
""" Clear borg.localroles cache.
borg.localroles check role implementation caches user/request combinations.
If we edit the roles for a user we need to clear this cache,
"""
from zope.annotation.interfaces import IAnnotations
ann = IAnnotations(self.app.REQUEST)
for key in list(ann.keys()): # Little destructive here, deletes *all* annotations
del ann[key]
Debugging¶
Set your breakpoint in
Products.PlonePAS.plugins.local_role.LocalRolesManager.getRolesInContext()
and
Products.PlonePAS.plugins.role.GroupAwareRoleManager.getRolesForPrincipal()
. There you see how roles for a given context are being
resolved.
Check the
acl_users.portal_role_manager
tool via the
ZMI.
Please see the zopyx.plone.cassandra add-on product.