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

Luis De la Parra lparrab at gmx.net
Wed Jul 4 19:45:11 EDT 2007


Sebastian Ware wrote:

> If someone explains security to me, I will be happy to write a mini
> tutorial for newbies (such as myself) :)

well.. I didn't know how to explain it if not with a mini tutorial, so here
it goes. Feel free to change it and publish it somewhere if you think it's
any good. --it has stuff about Forms and PAU, but I couldn't find a way to
strip that and still leave a good use-case example.

I don't know if the text-format is ok, or if there is a way to actually run
the examples like some kind of doctest.  Anyways... It would be a good if
someone who really knows about this could review it.  I extracted it from a
test-application I played with yesterday and it's working here, but I don't
know if I got everything correct.

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, Grok allows access to everythig unless you
explicitly restrict it.

[FIXME: is this really correct??? if yes, do we really need to explain it to
newbies ??]
Another difference is that the standard-Zope3 performs authorization checks
for the content objects, Grok makes the checks on the Views used to access
(display/manipulate) the objects.
[FIXME]


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 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 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 ViewContents and
#       EditContacts
#       this assumes you are using a Pluggable Authentication Utility /
PrincipalFolder
        pau = component.getUtility(IAuthentication)
        principals = pau['principals']
        principals[user] = 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):
        grok.require('mysite.AddContacts')  #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

        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)) #display the newly created
contact



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

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

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



Learning More
--------------
Permissions can be grouped together in Roles, which makes granting all the
permissions a particular type of user might need 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????]
    role_manager = IRolePermissionManager( grok.getSite() )

#   group all permissions in two roles: one for normal site members, and one
for admins
   
role_manager.grantPermissionToRole('mysite.ViewContacts', 'mysite.Member')
   
role_manager.grantPermissionToRole('mysite.AddContacts',  'mysite.Member')

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

#   If the context here is the Site/Application, users with the
Administrator role can
#   edit all ContactInfos, regardless who the creator is
    role_manager = IPrincipalRoleManager(context)
    role_manager.assignRoleToPrincipal('mysite.Administrator', principalID)





More information about the Grok-dev mailing list