[Grok-dev] Re: Re: Local permissions?

Luis De la Parra lparrab at gmx.net
Wed Aug 8 18:08:25 EDT 2007


Hi all,

I'm re-opening the thread on security/permissions from beginning of july.
Sebastian did proof-read it and made some comments on it, but I was over 3
weeks with tons of work and pretty much off-line, so I'm just starting to
catch up with stuff..

here it goes again, with sebastian's comments addressed..
cheers. luis



===========================
Newbie Permissions Tutorial
===========================

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


Setup
-----
::
    #contact.py
    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 defined above. If you want to restrict access to a view,
you have to explicitly protect it with a permission.

::

#   Define Permissions. This can be any string, but it is 
#   strongly recommended to make them unique by prefixing
#   them with the application name

    grok.define_permission('mysite.ViewContacts')
    grok.define_permission('mysite.AddContacts')
    grok.define_permission('mysite.EditContact')


    class ViewContactComplete(grok.View)
        """ Display Contact Info, inclusive 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: ' + contact.first_name + contact.last_name +
contact.email



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 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.securitypolicy.interfaces import
IPrincipalPermissionManager

    def addUser(username, password, realname):
        # create a new user and give him the authorizations ViewContacts and
        # EditContacts. This example assumes you are using a 
        # Pluggable Authentication Utility / 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 set for the context for which the PermissionManager is
created, and --if not explicitly overridden-- all it's children. The above
example gives the '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):         
        # 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') 

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

        @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):
        grok.require('mysite.EditContacts') #only users with
permission 'mysite.EditContacts' can use this

        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
--------------------
[FIXME How to check permissions in a page template and from python code?
User Interfaces should not contain any links/actions which users cannot
access / for which users don't have authorizations]


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

::
    from zope.app.securitypolicy.interfaces import IPrincipalRoleManager
    from zope.app.securitypolicy.interfaces import IRolePermissionManager

[FIXME: Roles have to be first defined / registered as a local Utility????]
[FIXME: As of July 2007, there has been some discussion on the mailing list
about simplifying role definitions. This section may be outdated]

    role_man = IRolePermissionManager( grok.getSite() )

As an example, let's group all permissions in two roles: one for normal site
members, and one for admins
   
::
    role_man.grantPermissionToRole('mysite.ViewContacts', 'mysite.Member')   
    role_man.grantPermissionToRole('mysite.AddContacts',  'mysite.Member')

role_man.grantPermissionToRole('mysite.ViewContacts', 'mysite.Administrator')
role_man.grantPermissionToRole('mysite.AddContacts',  'mysite.Administrator')
role_man.grantPermissionToRole('mysite.EditContacts', 'mysite.Administrator')

Now, if the context here is the Site/Application, users with the
Administrator role can edit all ContactInfos, regardless who the creator is

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





More information about the Grok-dev mailing list