[Zope-dev] Zope 2.3.0 AccessControl/SecurityInfo.py

Randall F. Kern randy@spoke.net
Thu, 1 Mar 2001 15:25:23 -0800


Sorry if these have already been fixed in 2.3.1, I haven't had time to
upgrade yet.

I fixed a small bug in SecurityInfo that made
SecurityInfo.setPermissionDefault() impossible to use:

191c191
>         self.roles[permission_name] =3D rdict.keys()
---
<         self.roles[permission_name] =3D rdict

    def setPermissionDefault(self, permission_name, roles):
        """Declare default roles for a permission"""
        rdict =3D {}
        for role in roles:
            rdict[role] =3D 1
        if self.roles.get(permission_name, rdict) !=3D rdict:
            LOG('SecurityInfo', WARNING, 'Conflicting default role'
                'declarations for permission "%s"' % permission_name)
            self._warnings =3D 1
        self.roles[permission_name] =3D rdict.keys()

My other problem was that I wanted to setup some default permissions
that are used programatically in my product (i.e. they aren't used to
protect any specific methods, but the methods themselves check for the
permission.)  A small change to ClassSecurityInfo.apply() allows you to
call SecurityInfo.setPermissionDefault() to create new permissions, even
if they aren't attached to any methods:

239a240,242
>         for permission_name in self.roles.keys():
>             if not ac_permissions.has_key(permission_name):
>                 ac_permissions[permission_name] =3D ()

    def apply(self, classobj):
        """Apply security information to the given class object."""

        dict =3D classobj.__dict__

        # Check the class for an existing __ac_permissions__ and
        # incorporate that if present to support older classes or
        # classes that haven't fully switched to using SecurityInfo.
        if dict.has_key('__ac_permissions__'):
            for item in dict['__ac_permissions__']:
                permission_name =3D item[0]
                self._setaccess(item[1], permission_name)
                if len(item) > 2:
                    self.setDefaultRoles(permission_name, item[2])

        # Set __roles__ for attributes declared public or private.
        # Collect protected attribute names in ac_permissions.
        ac_permissions =3D {}
        for name, access in self.names.items():
            if access in (ACCESS_PRIVATE, ACCESS_PUBLIC, ACCESS_NONE):
                dict['%s__roles__' % name] =3D access
            else:
                if not ac_permissions.has_key(access):
                    ac_permissions[access] =3D []
                ac_permissions[access].append(name)

        # Now transform our nested dict structure into the nested tuple
        # structure expected of __ac_permissions__ attributes and set
        # it on the class object.
        getRoles =3D self.roles.get
        __ac_permissions__ =3D []
        for permission_name in self.roles.keys():
            if not ac_permissions.has_key(permission_name):
                ac_permissions[permission_name] =3D ()
        permissions =3D ac_permissions.items()
        permissions.sort()
        for permission_name, names in permissions:
            roles =3D getRoles(permission_name, ())
            if len(roles):
                entry =3D (permission_name, tuple(names), tuple(roles))
            else:
                entry =3D (permission_name, tuple(names))
            __ac_permissions__.append(entry)
        dict['__ac_permissions__'] =3D tuple(__ac_permissions__)

        # Take care of default attribute access policy
        access =3D getattr(self, 'access', _marker)
        if access is not _marker:
            dict['__allow_access_to_unprotected_subobjects__'] =3D =
access

        if getattr(self, '_warnings', None):
            LOG('SecurityInfo', WARNING, 'Class "%s" had conflicting '
                'security declarations' % classobj.__name__)



-Randy