[Zope-Coders] Changes to ObjectManager, Role, and User in Zope2

Zachery Bir zbir at urbanape.com
Wed Mar 17 10:25:46 EST 2004


In trying to justify the changes I made (and then reverted, pending 
tests), I'd like to ask those here.

In OFS.ObjectManager._setObject:

	[... snip ...]
         if set_owner:
             object.manage_fixupOwnershipAfterAdd()

             # Try to give user the local role "Owner", but only if
             # no local roles have been set on the object yet.
             if hasattr(object, '__ac_local_roles__'):
                 if object.__ac_local_roles__ is None:
                     user=getSecurityManager().getUser()
                     if user is not None:
                         name=user.getUserName()
                         if name != 'Anonymous User':
                             object.manage_setLocalRoles(name, ['Owner'])

This goes against AccessControl.Role.manage_setLocalRoles' signature 
expectation of a userId:

     def manage_setLocalRoles(self, userid, roles, REQUEST=None):
         """Set local roles for a user."""
         if not roles:
             raise ValueError, 'One or more roles must be given!'
         dict=self.__ac_local_roles__ or {}
         dict[userid]=roles
         self.__ac_local_roles__=dict
         if REQUEST is not None:
             stat='Your changes have been saved.'
             return self.manage_listLocalRoles(self, REQUEST, stat=stat)

Especially, as that is how 
AccessControl.User.SimpleUser.getRolesInContext is intended to 
ascertain them:

     def getRolesInContext(self, object):
         """Return the list of roles assigned to the user,
            including local roles assigned in context of
            the passed in object."""
         userid=self.getId()
         roles=self.getRoles()
         local={}
         object=getattr(object, 'aq_inner', object)
         while 1:
             local_roles = getattr(object, '__ac_local_roles__', None)
             if local_roles:
                 if callable(local_roles):
                     local_roles=local_roles()
                 dict=local_roles or {}
                 for r in dict.get(userid, []):
                     local[r]=1
             inner = getattr(object, 'aq_inner', object)
             parent = getattr(inner, 'aq_parent', None)
             if parent is not None:
                 object = parent
                 continue
             if hasattr(object, 'im_self'):
                 object=object.im_self
                 object=getattr(object, 'aq_inner', object)
                 continue
             break
         roles=list(roles) + local.keys()
         return roles

So, as it is, while we except the Anonymous User from playing in 
setting the local role of Owner, we don't except the Emergency User 
from doing so, but in doing so, the Emergency User will never get back 
those roles assigned to it.

I propose the following changes to OFS.ObjectManager._setObject:

         if set_owner:
             object.manage_fixupOwnershipAfterAdd()

             # Try to give user the local role "Owner", but only if
             # no local roles have been set on the object yet.
             if hasattr(object, '__ac_local_roles__'):
                 if object.__ac_local_roles__ is None:
                     user=getSecurityManager().getUser()
                     if user is not None:
                         id=user.getId()
                         name=user.getUserName()
                         if name != 'Anonymous User':
                             object.manage_setLocalRoles(id, ['Owner'])

Again, preventing the Anonymous User from playing. This will then, 
however, put Anonymous User and Emergency User on the same level WRT 
AccessControl.User.SimpleUser.getRolesInContext (both would have access 
to the roles keyed to None).

So, an additional change could be implemented as such:

AccessControl.User:

class SpecialUser(SimpleUser):
     """Class for special users, like emergency user and nobody"""
     def getId(self): return self._id # instead of return 
self.getUserName()

[...]

info = readUserAccessFile('access')
if info:
     _remote_user_mode = info[3]
     emergency_user = UnrestrictedUser(
         info[0], info[1], ('manage',), info[2])
else:
     emergency_user = NullUnrestrictedUser()
emergency_user._id = '_emergency_user'

super = emergency_user  # Note: use of the 'super' name is deprecated.
del info


nobody=SpecialUser('Anonymous User','',('Anonymous',), [])
nobody._id = '_anonymous_user'
system=UnrestrictedUser('System Processes','',('manage',), [])
system._id = '_system_user'

These changes would ensure that the local_roles machinery WRT setting 
the Owner would work properly, and we'd have the foundation for 
disambiguation between usernames and userids

The only thing this might obscure is an intention to provide for 
emergency users and anonymous users to always share the same local 
roles (since both would be mapped to and accessed with None as the key)

Thoughts?

Zac





More information about the Zope-Coders mailing list