Personal tools
You are here: Home Documentation Tutorials Permissions Tutorial

Permissions Tutorial

Note: Return to tutorial view.

Zope 3 and Grok come with authorization capabilities out of the box. While a vanilla Zope 3 application protects all content by default and performs authorization checks on the content objects themselves, Grok allows access to everything unless you explicitly restrict it. The authorization checks here are done based on the Views used to access (display/manipulate) the content.

Setup Code

Imagine a Grok module for holding Contact Info called contact.py. By default, anyone is able to view the ViewContact view.
from zope import component, interface, schema
import grok

class IContactInfo(interface.Interface):
    """ Interface/Schema for Contact Information """
    first_name = schema.Text(title=u'First Name')
    last_name  = schema.Text(title=u'Last Name')
    email      = schema.Text(title=u'E-mail')


class ContactInfo(grok.Model):
    interface.implements(IContactInfo)

    first_name = ''
    last_name  = ''
    email = ''

class ViewContact(grok.View)
    """Display Contact Info, without e-mail.

    Anyone can use this view, even unauthenticated users
    over the internet
    """
    def render(self):
        contact = self.context
        return 'Contact: ' + contact.first_name + contact.last_name

Defining Permissions and restricting access

As all Views in Grok default to public access, anyone can use the ViewContact view. If you want to restrict access to a view, you have to explicitly protect it with a permission.

Define your Grok Permissions by subclassing from the grok.Permission base class. You must use the grok.name directive to give your permission a unique name. It can be any string, but it is strongly recommended to prefix them with the application name.

class ViewContacts(grok.Permission):
    grok.name('mysite.ViewContacts')
    grok.title('View Contacts') # optional

class AddContacts(grok.Permission):
    grok.name('mysite.AddContacts')

class EditContacts(grok.Permission):
    grok.name('mysite.EditContacts')

class ViewContactComplete(grok.View)
    """Display Contact Info, including email.

    Only users which have the permission 'mysite.ViewContacts'
    can use this view.
    """"
    grok.require('mysite.ViewContacts')  # this is the security declaration

    def render(self):
        contact = self.context
        return 'Contact: %s%s%s' % (contact.first_name,
                                    contact.last_name,
                                    contact.email)

Note The grok.Permission component base class was introduced after the release 0.10. In earlier versions of Grok a permission was defined using a module level directive, like so:

grok.define_permission('mysite.ViewContacts')

If you are using grokproject this change currently does not affect your installation. In this case use grok.define_permission as described above.

Granting Permissions

You can grant permissions to principals with a PermissionManager. For example, if all registered users should have permission to view contact details and to create new contacts, you could grant them the permissions when the user account is created.
from zope.app.security.interfaces import IAuthentication
from zope.app.authentication.principalfolder import InternalPrincipal

# note: the securitypolicy package was moved in Grok 0.12+ from zope.app. to zope.
from zope.securitypolicy.interfaces import IPrincipalPermissionManager

def addUser(username, password, realname):
    """Create a new user.

    create a new user and give it the authorizations,
    ``ViewContacts`` and ``EditContacts``. This example assumes
    you are using a Pluggable Authentication Utility (PAU) /
    PrincipalFolder, which you have to create and register when
    creating your Application.
    """

    pau = component.getUtility(IAuthentication)
    principals = pau['principals']
    principals[username] = InternalPrincipal(username, password, realname)

    # grant the user permission to view and create contacts
    # everywhere in the site
    permission_man = IPrincipalPermissionManager(grok.getSite())

    # NOTE that you need a principal ID. If you are
    # authenticating users with a PAU this is normally the user
    # name prepended with the principals-folder prefix (and the
    # PAU-prefix as well, if set)
    permission_man.grantPermissionToPrincipal (
       'mysite.ViewContacts',
       principals.prefix + username)
    permission_man.grantPermissionToPrincipal(
       'mysite.AddContacts',
       principals.prefix + username)

Permissions are granted for the context for which the PermissionManager is created, and -- if not explicitly overridden -- all its children. The above example grants View and Add permissions for the complete site, unless a folder down in the hierarchy revokes the permission.

If you want users to be able to edit only their own ContactInfos, you have to give them the Edit permission only within the context of the ContactInfo-object itself

class AddContact(grok.AddForm):
    """Add a contact.
    """

    # Only users with permission 'mysite.AddContacts' can use
    # this.
    #
    # NOTE that if you don't protect this Form, anyone -- even
    # anonymous/unauthenticated users -- could add ``Contacts``
    # to the site.
    grok.require('mysite.AddContacts')

    #automagically generate form fields
    form_fields = grok.AutoFields(IContactInfo)

    @grok.action('Create')
    def create(self, **kw):
        # Create and add the ``ContactInfo`` to our context
        # (normally a folder/container)
        contact = ContactInfo()
        self.applyData(contact, **kw)
        self.context[contact.first_name] = contact

        # Grant the current user the Edit permission, but only in
        # the context of the newly created object.
        permission_man = IPrincipalPermissionManager(contact)
        permission_man.grantPermissionToPrincipal(
            'mysite.EditContacts',
            self.request.principal.id)
        self.redirect(self.url(contact))

class EditContact(grok.EditForm):
    """Edit a contact.
    """

    #only users with permission 'mysite.EditContacts' can use this
    grok.require('mysite.EditContacts')

    form_fields = grok.AutoFields(IContactInfo)

    @grok.action('Save Changes')
    def edit(self, **data):
        self.applyData(self.context, **data)
        self.redirect(self.url(self.context))

Checking Permissions

How to check permission in python code

When generating user interface elements you might want to check that the current logged in principal actually can access a view to which a link refers. You need to do two things: 1 get the view, 2 check permissions on that view. This is how you do it:

from zope.component import getMultiAdapter
from zope.security import canAccess

def canAccessView(obj, view_name):
    # obj - is the object you want view
    # view_name - is the grok.View/AddForm/EditForm you want to access
    view = getMultiAdapter((obj, self.request), name=view_name)
    # check if you can access the __call__ method which is equal
    # to being allowed to access this view.
    return canAccess(view, '__call__')

If you want to check if the current logged in principal has a specific permission on a specific object or view you can do so by means of the checkPermission method. It is available through zope.security and in a view through self.request.interaction. Note that Grok doesn't allow a simplified way of setting object level permissions. The grok.requires statement is only applicable to views.

from zope.security import checkPermission
def justChecking(context):
    # context - the object or view you are checking permissions on
    user_allowed = checkPermission(PERMISSION_NAME, context)

class MyView(grok.View):
    def update(self):
        i = self.request.interaction
        # checking permission on currently viewed object (self.context)
        user_allowed = i.checkPermission(PERMISSION_NAME, self.context)

Defining Roles

Permissions can be grouped together in Roles, which makes granting all the permissions for a particular type of user much easier. Defining roles is similar to defining permissions.

As an example, let's group all permissions in two roles: one for normal site members, and one for administrators:

class MemberRole(grok.Role):
    grok.name('mysite.Member')
    grok.title('Contacts Member') # optional
    grok.permissions(
        'mysite.ViewContacts',
        'mysite.AddContacts')

class AdministratorRole(grok.Role):
    grok.name('mysite.Administrator')
    grok.title('Contacts Administrator') # optional
    grok.permissions(
        'mysite.ViewContacts',
        'mysite.AddContacts',
        'mysite.EditContacts')

Now, if the context here is the site/application, users with the administrator role can edit all ContactInfos, regardless of who the creator is.

# note: securitypolicy package moved in Grok 0.12+ from zope.app. to zope.
from zope.securitypolicy.interfaces import IPrincipalRoleManager

role_man = IPrincipalRoleManager(context)
role_man.assignRoleToPrincipal('mysite.Administrator', principalID)