[Zope-dev] Suggestion: Blocking out Localroles?

Lennart Regebro lennart@regebro.nu
Mon, 29 Oct 2001 23:26:58 +0100


This is a multi-part message in MIME format.

------=_NextPart_000_005D_01C160D1.347FB2E0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

I was going to put this up as a proposal, but I can't figure out how to add
a new proposal... :-) Then I checked out the new collector, and there is a
possibility to add a "feature" there too, so maybe this fits better there?

Anyway, heres the suggestion:

When developing a CM system in Zope a customer asked for a possibility to
"block out" a persons local role lower down in the hierarchy. That way a
person that has manager rights on a country-level could have these rights
removed on a regional level.

So, we implemented this as a HotFix, that seems to work fine. It also has a
user interface for local roles that is somewhat easier (in my opinion) to
use.

So what do you think? Is this stupid or good? Is it a "feature" or a
"proposal"?

I attached the files, you can put the __init__.py in any directory under
Products, and the dtml-files in a directory 'dtml' under that if you want to
try it out. I think it should work with a clean Zope installation (although
we haven't tested that for a couple of weeks).

------=_NextPart_000_005D_01C160D1.347FB2E0
Content-Type: application/octet-stream;
	name="__init__.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="__init__.py"

print """Hotfixing: AccessControl: Extending Local Roles,
           Lennart Regebro, 2001-10-04, version Easy Publisher 1.4.38"""

from AccessControl.Role import RoleManager
from AccessControl.User import BasicUser
import Globals
from Globals import DTMLFile
from App.Common import aq_base
from string import join
from AccessControl import ClassSecurityInfo
from urllib import quote

securityRoleManager =3D ClassSecurityInfo()

# Local roles support
# -------------------
#
# Local roles allow a user to be given extra roles in the context
# of a particular object (and its children). When a user is given
# extra roles in a particular object, an entry for that user is made
# in the __ac_local_roles__ dict containing the extra roles.

#__ac_local_roles__=3DNone

#TODO: New methods need to have "Change permissions" premissions defined =
for them

__ac_local_roles_white__ =3D {}
__ac_local_roles_black__ =3D {}
RoleManager.__ac_local_roles_white__ =3D __ac_local_roles_white__
RoleManager.__ac_local_roles_black__ =3D __ac_local_roles_black__

manage_listLocalRoles=3DDTMLFile('dtml/listLocalRoles', globals(),
                               management_view=3D'Security',
                               help_topic=3D'Security_Local-Roles.stx',
                               help_product=3D'OFSP')

RoleManager.manage_listLocalRoles =3D manage_listLocalRoles

manage_editLocalRoles=3DDTMLFile('dtml/editLocalRoles', globals(),
                               management_view=3D'Security',
                               =
help_topic=3D'Security_User-Local-Roles.stx',
                               help_product=3D'OFSP')

RoleManager.manage_editLocalRoles =3D manage_editLocalRoles


def has_local_roles(self):
    dict=3Dself.__ac_local_roles__()
    return len(dict)

RoleManager.has_local_roles =3D has_local_roles

def get_local_roles(self):
    dict=3Dself.__ac_local_roles__()
    keys=3Ddict.keys()
    keys.sort()
    info=3D[]
    for key in keys:
        value=3Dtuple(dict[key])
        info.append((key, value))
    return tuple(info)

RoleManager.get_local_roles =3D get_local_roles

def get_valid_userids(self):
    item=3Dself
    dict=3D{}
    while 1:
        if hasattr(aq_base(item), 'acl_users') and \
           hasattr(item.acl_users, 'user_names'):
            for name in item.acl_users.user_names():
                dict[name]=3D1
        if not hasattr(item, 'aq_parent'):
            break
        item=3Ditem.aq_parent
    keys=3Ddict.keys()
    keys.sort()
    return tuple(keys)

RoleManager.get_valid_userids =3D get_valid_userids

securityRoleManager.declarePrivate('possible_contributers')
RoleManager.possible_contributers =3D get_valid_userids

securityRoleManager.declarePrivate('get_valid_userids_for_role')
def get_valid_userids_for_role(self, role):
    item=3Dself
    dict=3D{}
    while 1:
        if hasattr(aq_base(item), 'acl_users') and \
           hasattr(item.acl_users, 'getUsers'):
            for user in item.acl_users.getUsers():
                if not dict.has_key(user.getId()) and =
user.has_role(role, object=3Dself):
                    dict[user.getId()]=3D1
        if not hasattr(item, 'aq_parent'):
            break
        item=3Ditem.aq_parent
    keys=3Ddict.keys()
    keys.sort()
    return tuple(keys)

RoleManager.get_valid_userids_for_role =3D get_valid_userids_for_role


def get_local_roles_for_userid(self, userid):
    #PATCH: temporary patch code
    if not callable(self.__ac_local_roles__): del =
self.__ac_local_roles__
    dict=3Dself.__ac_local_roles__()
    return tuple(dict.get(userid, []))

RoleManager.get_local_roles_for_userid =3D get_local_roles_for_userid

def manage_addLocalRoles(self, userid, roles, REQUEST=3DNone, =
RESPONSE=3DNone):
    """Set local roles for a user."""
    if not roles:
        raise ValueError, 'One or more roles must be given!'
    dict=3Dself.__ac_local_roles__()
    local_roles =3D list(dict.get(userid, []))
    for r in roles:
        if r not in local_roles:
            local_roles.append(r)
    dict[userid] =3D local_roles
    self.setLocalRoles(dict)
    if REQUEST and RESPONSE:
        message=3D"Your changes have been saved."
        =
RESPONSE.redirect('%s/manage_listLocalRoles?manage_tabs_message=3D%s' % =
(REQUEST.URL1, quote(message)))

RoleManager.manage_addLocalRoles =3D manage_addLocalRoles

def manage_setLocalRoles(self, userid, roles, REQUEST=3DNone, =
RESPONSE=3DNone):
    """Set local roles for a user."""
    if not roles:
        raise ValueError, 'One or more roles must be given!'
    dict=3Dself.__ac_local_roles__()
    dict[userid]=3Droles
    self.setLocalRoles(dict)
    if REQUEST and RESPONSE:
        message=3D"Your changes have been saved."
        =
RESPONSE.redirect('%s/manage_listLocalRoles?manage_tabs_message=3D%s' % =
(REQUEST.URL1, quote(message)))

RoleManager.manage_setLocalRoles =3D manage_setLocalRoles

def manage_delLocalRoles(self, userids, REQUEST=3DNone, =
RESPONSE=3DNone):
    """Remove all local roles for a user."""
    dict=3Dself.__ac_local_roles__()
    for userid in userids:
        if dict.has_key(userid):
            del dict[userid]
    self.setLocalRoles(dict)
    if REQUEST and RESPONSE:
        message=3D"Users added as local authors."
        =
RESPONSE.redirect('%s/manage_listLocalRoles?manage_tabs_message=3D%s' % =
(REQUEST.URL1, quote(message)))

RoleManager.manage_delLocalRoles =3D manage_delLocalRoles


def __ac_local_roles__(self):
    local_roles =3D self.__ac_local_roles_white__ or {}
    local_roles =3D local_roles.copy()
    black =3D self.__ac_local_roles_black__ or {}
    blackusers =3D black.keys()
    for user, roles in local_roles.items():
        if user in blackusers:
            local_roles[user] =3D filter(lambda r, br=3Dblack[user]: r =
not in br, roles)
    return local_roles

RoleManager.__ac_local_roles__ =3D __ac_local_roles__


securityRoleManager.declarePrivate('setLocalRoles')
def setLocalRoles(self, local_roles_white):
    self.__ac_local_roles_white__=3Dlocal_roles_white

RoleManager.setLocalRoles =3D setLocalRoles


securityRoleManager.declarePrivate('setLocalRolesBlack')
def setLocalRolesBlack(self, local_roles_black):
    self.__ac_local_roles_black__=3Dlocal_roles_black

securityRoleManager.declarePrivate('getBlackRolesForUser')
def getBlackRolesForUser(self, user):
    return self.__ac_local_roles_black__.get(user, ())

securityRoleManager.declarePrivate('getBlackList')
def getBlackList(self, user):
    return self.__ac_local_roles_black__

RoleManager.setLocalRolesBlack =3D setLocalRolesBlack
RoleManager.getBlackRolesForUser =3D getBlackRolesForUser
RoleManager.getBlackList =3D getBlackList


# local_roles_with_hop
# {
#   'user1': {role1: hop0, role2: hop1, role3: hop0 },
#   'user2': {role1: hop1, role2: hop1, role3: hop1 },
# }

securityRoleManager.declarePrivate('get_local_roles_aq')
def get_local_roles_aq(self):
    hop=3D-1
    local_roles =3D {}
    black_roles =3D {}
    inner_obj =3D getattr(self, 'aq_inner', self)
    while 1:
        hop=3Dhop + 1
        current_local_roles =3D =
getattr(inner_obj,'__ac_local_roles_white__',None)
        current_black_roles =3D =
getattr(inner_obj,'__ac_local_roles_black__',None)
        if current_black_roles is not None:
            for user, roles in current_black_roles.items():
                if not black_roles.has_key(user):
                    black_roles[user] =3D ()
                black_roles[user] =3D black_roles[user] + roles
        if current_local_roles is not None:
            for user, roles in current_local_roles.items():
                b_roles =3D black_roles.get(user, ())
                for role in roles:
                    if not local_roles.has_key(user):
                      local_roles[user] =3D {}
                    if (role not in local_roles[user].keys()) and (role =
not in b_roles):
                        local_roles[user][role] =3D hop
        inner =3D getattr(inner_obj, 'aq_inner', inner_obj)
        parent =3D getattr(inner, 'aq_parent', None)
        if parent is not None:
            inner_obj =3D parent
            continue
        if hasattr(inner_obj, 'im_self'):
            inner_obj=3Dinner_obj.im_self
            inner_obj=3Dgetattr(inner_obj, 'aq_inner', inner_obj)
            continue
        break
    return local_roles


RoleManager.get_local_roles_aq =3D get_local_roles_aq

securityRoleManager.declarePrivate('filter_acquired_roles_for_userid')
def filter_acquired_roles_for_userid(self, userid, =
local_roles_with_hop=3DNone):
    if local_roles_with_hop is None: local_roles_with_hop=3D {}
    if local_roles_with_hop.has_key(userid):
        return map(lambda (role, hop): role,filter(lambda (role, hop): =
hop!=3D0, local_roles_with_hop[userid].items()))
    return []

RoleManager.filter_acquired_roles_for_userid =3D =
filter_acquired_roles_for_userid

securityRoleManager.declarePrivate('getUserById')
def getUserById(self, userid):
    item=3Dself
    while 1:
        if hasattr(aq_base(item), 'acl_users') and \
           hasattr(item.acl_users, 'user_names'):
            for name in item.acl_users.user_names():
                if userid =3D=3D name:
                    #The User object needs to be in the context of the
                    #user folder that contains it.
                    return =
item.acl_users.getUser(userid).__of__(item.acl_users)
        if not hasattr(item, 'aq_parent'):
            break
        item=3Ditem.aq_parent
    return None

RoleManager.getUserById =3D getUserById


securityRoleManager.declareProtected('Change permissions', =
'manage_addLocalRolesForUsers')
def manage_addLocalRolesForUsers(self, userids=3DNone, roles=3DNone, =
REQUEST=3DNone, RESPONSE=3DNone):
    """Add Local Users"""
    if roles is None: roles=3D[]
    if userids is None: userids=3D[]
    local_roles_white =3D self.__ac_local_roles_white__
    for user in userids:
        users_white_roles =3D list(local_roles_white[user])
        for role in roles:
            if role not in users_white_roles: =
users_white_roles.append(role)
        local_roles_white[user] =3D tuple(users_white_roles)
    self.setLocalRoles(local_roles_white)
    if REQUEST and RESPONSE:
        message=3D"Lennart has been blacklisted as Author."
        =
RESPONSE.redirect('%s/manage_listLocalRoles?manage_tabs_message=3D%s' % =
(REQUEST.URL1, quote(message)))

RoleManager.manage_addLocalRolesForUsers =3D =
manage_addLocalRolesForUsers

securityRoleManager.declareProtected('Change permissions', =
'manage_delLocalRolesForUsers')
def manage_delLocalRolesForUsers(self, userids=3DNone, roles=3DNone, =
REQUEST=3DNone, RESPONSE=3DNone):
    """Delete Local Users"""
    if roles is None: roles=3D[]
    if userids is None: userids=3D[]
    local_roles_white =3D self.__ac_local_roles_white__
    for user in userids:
        users_white_roles =3D list(local_roles_white[user])
        for role in roles:
            if role in users_white_roles: users_white_roles.remove(role)
        local_roles_white[user] =3D tuple(users_white_roles)
    self.setLocalRoles(local_roles_white)
    if REQUEST and RESPONSE:
        message=3D"[%s] has been given the role(s): [%s]." % =
(join(userids, ', '),join(roles, ', '))
        =
RESPONSE.redirect('%s/manage_listLocalRoles?manage_tabs_message=3D%s' % =
(REQUEST.URL1, quote(message)))

RoleManager.manage_delLocalRolesForUsers =3D =
manage_delLocalRolesForUsers

securityRoleManager.declareProtected('Change permissions', =
'manage_disableLocalRolesForUsers')
def manage_disableLocalRolesForUsers(self, userids=3DNone, roles=3DNone, =
REQUEST=3DNone, RESPONSE=3DNone):
    """Disable users from Local Role Access"""
    if roles is None: roles=3D[]
    if userids is None: userids=3D[]
    local_roles_black =3D self.__ac_local_roles_black__
    for user in userids:
        users_black_roles =3D list(local_roles_black.get(user,()))
        for role in roles:
            if role not in users_black_roles: =
users_black_roles.append(role)
        local_roles_black[user] =3D tuple(users_black_roles)
    self.setLocalRolesBlack(local_roles_black)
    if REQUEST and RESPONSE:
        message=3D"[%s] has been removed as local role(s): [%s]."  % =
(join(userids, ', '),join(roles, ', '))
        =
RESPONSE.redirect('%s/manage_listLocalRoles?manage_tabs_message=3D%s' % =
(REQUEST.URL1, quote(message)))

RoleManager.manage_disableLocalRolesForUsers =3D =
manage_disableLocalRolesForUsers

securityRoleManager.declareProtected('Change permissions', =
'manage_enableLocalRolesForUsers')
def manage_enableLocalRolesForUsers(self, userids=3DNone, roles=3DNone, =
REQUEST=3DNone, RESPONSE=3DNone):
    """Enable disabled users from Local Role Access"""
    if roles is None: roles=3D[]
    if userids is None: userids=3D[]
    local_roles_black =3D self.__ac_local_roles_black__
    for user in userids:
        users_black_roles =3D list(local_roles_black.get(user,()))
        for role in roles:
            if role in users_black_roles: users_black_roles.remove(role)
        local_roles_black[user] =3D tuple(users_black_roles)
    self.setLocalRolesBlack(local_roles_black)
    if REQUEST and RESPONSE:
        message=3D"%s has been enabled as %s." % (join(userids,', =
'),join(roles,', '))
        =
RESPONSE.redirect('%s/manage_listLocalRoles?manage_tabs_message=3D%s' % =
(REQUEST.URL1, quote(message)))

RoleManager.manage_enableLocalRolesForUsers =3D =
manage_enableLocalRolesForUsers


RoleManager.security =3D securityRoleManager
Globals.InitializeClass(RoleManager)


# =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
# PATCH OF AccessControl.User.py

securityBasicUser =3D ClassSecurityInfo()

def getRolesInContext(self, object):
    """
    Return the list of roles assigned to the user,
    including local roles assigned in context of
    the passed in object.
    """
    name=3Dself.getUserName()
    roles=3Dself.getRoles()
    black_roles =3D ()
    inner_obj =3D getattr(object, 'aq_inner', object)
    while 1:
        current_local_roles =3D =
getattr(inner_obj,'__ac_local_roles_white__',None)
        current_black_roles =3D =
getattr(inner_obj,'__ac_local_roles_black__',None)
        if current_black_roles is not None:
            black_roles =3D black_roles + current_black_roles.get(name, =
())
        if current_local_roles is not None:
            for local_role in current_local_roles.get(name, ()):
                if (local_role not in roles) and (local_role not in =
black_roles):
                    roles =3D roles + (local_role,)
        inner =3D getattr(inner_obj, 'aq_inner', inner_obj)
        parent =3D getattr(inner, 'aq_parent', None)
        if parent is not None:
            inner_obj =3D parent
            continue
        if hasattr(inner_obj, 'im_self'):
            inner_obj=3Dinner_obj.im_self
            inner_obj=3Dgetattr(inner_obj, 'aq_inner', inner_obj)
            continue
        break
    return roles

BasicUser.getRolesInContext =3D getRolesInContext

def allowed(self, object, object_roles=3DNone):
    """Check whether the user has access to object. The user must
       have one of the roles in object_roles to allow access."""

    # Short-circuit the common case of anonymous access.
    if object_roles is None or 'Anonymous' in object_roles:
        return 1

    # Check for ancient role data up front, convert if found.
    # This should almost never happen, and should probably be
    # deprecated at some point.
    if 'Shared' in object_roles:
        object_roles =3D self._shared_roles(object)
        if object_roles is None or 'Anonymous' in object_roles:
            return 1

    # Check for a role match with the normal roles given to
    # the user, then with local roles only if necessary. We
    # want to avoid as much overhead as possible.
    user_roles =3D self.getRoles()
    for role in object_roles:
        if role in user_roles:
            if self._check_context(object):
                return 1
            return None

    # Still have not found a match, so check local roles. We do
    # this manually rather than call getRolesInContext so that
    # we can incur only the overhead required to find a match.

    inner_obj =3D getattr(object, 'aq_inner', object)
    name=3Dself.getUserName()
    black_roles =3D ()
    while 1:
        current_local_roles =3D =
getattr(inner_obj,'__ac_local_roles_white__',None)
        current_black_roles =3D =
getattr(inner_obj,'__ac_local_roles_black__',None)
        if current_black_roles is not None:
            black_roles =3D black_roles + current_black_roles.get(name, =
())
        if current_local_roles is not None:
            local_roles =3D current_local_roles.get(name, [])
            for role in object_roles:
                if role in local_roles and role not in black_roles:
                    if self._check_context(object):
                        return 1
                    return None
        inner =3D getattr(inner_obj, 'aq_inner', inner_obj)
        parent =3D getattr(inner, 'aq_parent', None)
        if parent is not None:
            inner_obj =3D parent
            continue
        if hasattr(inner_obj, 'im_self'):
            inner_obj=3Dinner_obj.im_self
            inner_obj=3Dgetattr(inner_obj, 'aq_inner', inner_obj)
            continue
        break
    return None

BasicUser.allowed =3D allowed

BasicUser.security =3D securityBasicUser
Globals.InitializeClass(BasicUser)


------=_NextPart_000_005D_01C160D1.347FB2E0
Content-Type: application/octet-stream;
	name="listLocalRoles.dtml"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="listLocalRoles.dtml"

<dtml-var manage_page_header>
<dtml-with "_(management_view=3D'LocalRoles')">
<dtml-if manage_tabs><dtml-var manage_tabs></dtml-if>
</dtml-with>

<h1 class=3D"strong-header">Manage Local Roles</h1>

<p class=3D"form-help">
Local roles allow you to give particular users extra roles in the =
context
of this object, in addition to the roles they already have.
</p>
<dtml-let local_roles_aq=3D"get_local_roles_aq()">
<dtml-if local_roles_aq>
<p class=3D"form-help">
The following users have been given local roles. To modify the local =
roles
given to a particular user, click on the name of the user.
</p>

<form action=3D"&dtml-URL1;" method=3D"POST">
<table cellspacing=3D"0" cellpadding=3D"0" border=3D"0">
<tr  class=3D"list-header">
  <td align=3D"left" valign=3D"middle"></td>
  <td align=3D"left" valign=3D"middle" class=3D"form-label" =
style=3D"padding:2px 20px 2px 4px">User</td>
  <td align=3D"left" valign=3D"middle" class=3D"form-label" =
style=3D"padding:2px 20px 2px 4px">Global Roles</td>
  <td align=3D"left" valign=3D"middle" style=3D"padding:2px 20px 2px =
4px"><span class=3D"form-label">Local Roles </span></td>
  <td align=3D"left" valign=3D"middle" class=3D"form-label" =
style=3D"padding:2px 20px 2px 4px">Effective Roles</td>
</tr>
<tr><td colspan=3D"5"></td></tr>

<dtml-in "local_roles_aq.items()">
<tr>
  <td align=3D"left" valign=3D"top">
    <input type=3D"checkbox" name=3D"userids:list" value=3D"<dtml-var =
sequence-key html_quote>" />
  </td>
  <td align=3D"left" valign=3D"top" class=3D"form-text" =
style=3D"padding:2px 20px 2px 4px">
    <a href=3D"manage_editLocalRoles?userid=3D<dtml-var sequence-key =
fmt=3D"url-quote">"><dtml-var sequence-key></a>
  </div>
  </td>
  <td align=3D"left" valign=3D"top" class=3D"form-text" =
style=3D"padding:2px 20px 2px 4px">
    <dtml-in "getUserById(_['sequence-key']).getRoles()">
        <dtml-var sequence-item><dtml-unless sequence-end>, =
</dtml-unless>
    </dtml-in>
  </td>
  <td align=3D"left" valign=3D"top" class=3D"form-text" =
style=3D"padding:2px 20px 2px 4px">
    <dtml-let locals=3D"get_local_roles_for_userid(_['sequence-key'])"  =
aq_locals=3D"filter_acquired_roles_for_userid(_['sequence-key'], =
local_roles_aq)" blacks=3D"getBlackRolesForUser(_['sequence-key'])">
      <dtml-in locals>
        <dtml-var sequence-item><dtml-unless "not aq_locals and not =
blacks and _['sequence-end']">, </dtml-unless>
      </dtml-in>
      <span style=3D"color:#000099">
        <dtml-in aq_locals>
            <dtml-var sequence-item>++<dtml-unless "not blacks and =
_['sequence-end']">, </dtml-unless>
        </dtml-in>
      </span>
      <span style=3D"color:#990000">
        <dtml-in blacks>
            <dtml-var sequence-item>--<dtml-unless sequence-end>, =
</dtml-unless>
        </dtml-in>
      </span>
    </dtml-let>
  </td>
  <td align=3D"left" valign=3D"top" class=3D"form-text" =
style=3D"padding:2px 20px 2px 4px">
    <dtml-in "getUserById(_['sequence-key']).getRolesInContext(this())">
        <dtml-var sequence-item><dtml-unless sequence-end>, =
</dtml-unless>
    </dtml-in>
  </td>
</tr>
</dtml-in>

<tr><td colspan=3D"5" height=3D"6"></td></tr>
<tr>
    <td>&nbsp;</td>
    <td colspan=3D"4" class=3D"form-text"><em>
    Symbols: LocalRole, <span style=3D"color:#000099">Acquired++</span>, =
and <span style=3D"color:#990000">Disabled--</span><br>
    (Disabling only applies to localy defined roles or acquired local =
roles.)</em>
    </td>
</tr>
<tr><td colspan=3D"5" height=3D"8"></td></tr>
<tr>
  <td align=3D"left" valign=3D"top">
  </td>
  <td align=3D"left" valign=3D"top" colspan=3D"4" =
class=3D"form-element">
    <input class=3D"form-element" type=3D"submit" =
name=3D"manage_addLocalRolesForUsers:method" value=3D"Add Local Role(s)" =
/>
    <input class=3D"form-element" type=3D"submit" =
name=3D"manage_delLocalRolesForUsers:method" value=3D"Remove Local =
Role(s)" />
    <input class=3D"form-element" type=3D"submit" =
name=3D"manage_disableLocalRolesForUsers:method" value=3D"Disable Local =
Role(s)" />
    <input class=3D"form-element" type=3D"submit" =
name=3D"manage_enableLocalRolesForUsers:method" value=3D"Enable Local =
Role(s)" />
    <br>
    <select name=3D"roles:list" size=3D"5" multiple>
      <dtml-in valid_roles>
        <dtml-if "_vars['sequence-item'] not in ('Anonymous', =
'Shared')">
          <option value=3D"<dtml-var sequence-item =
html_quote>"><dtml-var sequence-item></option>
        </dtml-if>
      </dtml-in>
    </select>
  </td>
</tr>
</table>
</form>
</dtml-if>
</dtml-let>

<h2 class=3D"form-title">Add a Local User</h2>
<p>
To give a user extra roles when accessing this object (and its =
children),
select a user from the <em>User</em> list below, select the extra
roles that should be given to that user from the <em>Roles</em> list.
</p>

<form action=3D"manage_setLocalRoles" method=3D"POST">
<table cellpadding=3D"2" cellspacing=3D"0" border=3D"0">
<tr>
  <td align=3D"left" valign=3D"top">
  <div class=3D"form-label">
  User
  </div>
  </td>
  <td align=3D"left" valign=3D"top">
  <div class=3D"form-label">
  Roles
  </div>
  </td>
</tr>
<tr>
  <td align=3D"left" valign=3D"top">
  <div class=3D"form-element">
  <select name=3D"userid" size=3D"5">
  <dtml-in get_valid_userids>
  <option value=3D"<dtml-var sequence-item html_quote>"><dtml-var
   sequence-item></option>
  </dtml-in>
  </select>
  </div>
  </td>
  <td align=3D"left" valign=3D"top">
  <div class=3D"form-element">
  <select name=3D"roles:list" size=3D"5" multiple>
<dtml-in valid_roles><dtml-if
"_vars['sequence-item'] not in ('Anonymous', 'Shared')">
<option value=3D"<dtml-var sequence-item html_quote>"><dtml-var
 sequence-item></option>
</dtml-if>
</dtml-in>
  </select>
  </div>
  </td>
</tr>
<tr>
  <td align=3D"left" valign=3D"top">
  <div class=3D"form-element">
  <input class=3D"form-element" type=3D"submit" name=3D"submit" =
value=3D" Add " />
  </div>
  </td>
  <td></td>
</tr>
</table>
</form>

<dtml-var manage_page_footer>

------=_NextPart_000_005D_01C160D1.347FB2E0
Content-Type: application/octet-stream;
	name="editLocalRoles.dtml"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="editLocalRoles.dtml"

<dtml-var manage_page_header>
<dtml-with "_(management_view='Security')">
<dtml-if manage_tabs><dtml-var manage_tabs></dtml-if>
</dtml-with>
<p class="form-help">
Local roles allow you to give particular users extra roles in the 
context of this object, in addition to the roles they already have. 
</p>

<p class="form-help">
To change the local roles for this user, select the extra roles this 
user should have in the context of this object and click the <em>
Save Changes</em> button.
</p>

<form action="manage_setLocalRoles" method="post">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
  <td align="left" valign="top">
  <div class="form-label">User</div>
  </td>
  <td align="left" valign="top">
  <div class="form-label">Roles</div>
  </td>
</tr>
<tr>
  <td align="left" valign="top">
  <div class="form-text"><dtml-var userid></div>
  </td>
  <td align="left" valign="top">
  <div class="form-element">
  <input type="hidden" name="userid" value="<dtml-var userid html_quote>">
<dtml-with "_(user_roles=get_local_roles_for_userid(userid))">
  <select name="roles:list" size="5" multiple>
<dtml-in valid_roles><dtml-if 
"_vars['sequence-item'] not in ('Anonymous', 'Shared')">
<option value="<dtml-var sequence-item html_quote>"<dtml-if 
"_['sequence-item'] in user_roles"> selected</dtml-if>><dtml-var 
sequence-item>
</dtml-if>
</dtml-in>
  </select>
</dtml-with>
  </div>
  </td>
</tr>
<tr>
  <td align="left" valign="top" colspan="2">
  <div class="form-element">
  <input class="form-element" type="submit" value="Save Changes" />
  </div>
  </td>
</tr>
</table>
</form>

<dtml-var manage_page_footer>

------=_NextPart_000_005D_01C160D1.347FB2E0--