[Zope] Unexplained Slowdown

Brian Lloyd brian@digicool.com
Wed, 17 Jan 2001 16:10:59 -0500


This is a multi-part message in MIME format.

------=_NextPart_000_0021_01C080A0.1469E1E0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

This is due to an ill-fated attempt to make 'domain-based 
authentication' less expensive (but that backfired to some 
extent because it can make non domain-based auth more 
expensive, especially if reverse DNS lookups are slow for 
you). This is fixed for 2.3 b2 - in the meantime you should be 
able to copy the attached User.py to fix the problem for 
now.


Brian Lloyd        brian@digicool.com
Software Engineer  540.371.6909              
Digital Creations  http://www.digicool.com 




> -----Original Message-----
> From: zope-admin@zope.org [mailto:zope-admin@zope.org]On Behalf Of Ian
> Thomas
> Sent: Wednesday, January 17, 2001 3:41 PM
> To: zope@zope.org
> Subject: [Zope] Unexplained Slowdown
> 
> 
> When I upgraded to Zope 2.2.5 access to my Zope over the web slowed down
> dramatically and I haven't been able to figure out why. I am interested
> in ideas I can try to track it down the problem or at least
> quantify/benchmark the slowness. 
> 
> Some background.
> 1) I am a computer teacher teaching Zope to my second year web
> development students who have already learned HTML and been introduced
> to JavaScript. 
> 2) The server is a my test machine that my students and I use for
> learning.
> 3) The "production" server still running 2.2.4 continues to preform
> normally.
> 4) The machine is Celeron 500 mhz 64 meg ram running Windows 2000 Server
> 5) I run Medusa server that comes with Zope to server the web pages.
> 6) There is no gateway set up on this machine so that it is only visible
> from within the school.
> 
> Notes.
> 1) It is much faster if I access via localhost on the server.
> 
> What I have tried.
> 1) Installing 2.2.4 on another port. It ran just as slow.
> 2) Today I removed the 2.2.4 installation and installed 2.3beta, again
> it seems just as slow.
> 
> What Next?
> The next thing I was thinking was to serve the webpages from IIS using
> PCGI.
> I am interested in other ideas.
> 
> I. Thomas
> 
> 
> 
> 
> 
> _______________________________________________
> Zope maillist  -  Zope@zope.org
> http://lists.zope.org/mailman/listinfo/zope
> **   No cross posts or HTML encoding!  **
> (Related lists - 
>  http://lists.zope.org/mailman/listinfo/zope-announce
>  http://lists.zope.org/mailman/listinfo/zope-dev )
> 
> 
------=_NextPart_000_0021_01C080A0.1469E1E0
Content-Type: text/plain;
	name="User.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="User.py"

#########################################################################=
#####=0A=
# =0A=
# Zope Public License (ZPL) Version 1.0=0A=
# -------------------------------------=0A=
# =0A=
# Copyright (c) Digital Creations.  All rights reserved.=0A=
# =0A=
# This license has been certified as Open Source(tm).=0A=
# =0A=
# Redistribution and use in source and binary forms, with or without=0A=
# modification, are permitted provided that the following conditions are=0A=
# met:=0A=
# =0A=
# 1. Redistributions in source code must retain the above copyright=0A=
#    notice, this list of conditions, and the following disclaimer.=0A=
# =0A=
# 2. Redistributions in binary form must reproduce the above copyright=0A=
#    notice, this list of conditions, and the following disclaimer in=0A=
#    the documentation and/or other materials provided with the=0A=
#    distribution.=0A=
# =0A=
# 3. Digital Creations requests that attribution be given to Zope=0A=
#    in any manner possible. Zope includes a "Powered by Zope"=0A=
#    button that is installed by default. While it is not a license=0A=
#    violation to remove this button, it is requested that the=0A=
#    attribution remain. A significant investment has been put=0A=
#    into Zope, and this effort will continue if the Zope community=0A=
#    continues to grow. This is one way to assure that growth.=0A=
# =0A=
# 4. All advertising materials and documentation mentioning=0A=
#    features derived from or use of this software must display=0A=
#    the following acknowledgement:=0A=
# =0A=
#      "This product includes software developed by Digital Creations=0A=
#      for use in the Z Object Publishing Environment=0A=
#      (http://www.zope.org/)."=0A=
# =0A=
#    In the event that the product being advertised includes an=0A=
#    intact Zope distribution (with copyright and license included)=0A=
#    then this clause is waived.=0A=
# =0A=
# 5. Names associated with Zope or Digital Creations must not be used to=0A=
#    endorse or promote products derived from this software without=0A=
#    prior written permission from Digital Creations.=0A=
# =0A=
# 6. Modified redistributions of any form whatsoever must retain=0A=
#    the following acknowledgment:=0A=
# =0A=
#      "This product includes software developed by Digital Creations=0A=
#      for use in the Z Object Publishing Environment=0A=
#      (http://www.zope.org/)."=0A=
# =0A=
#    Intact (re-)distributions of any official Zope release do not=0A=
#    require an external acknowledgement.=0A=
# =0A=
# 7. Modifications are encouraged but must be packaged separately as=0A=
#    patches to official Zope releases.  Distributions that do not=0A=
#    clearly separate the patches from the original work must be clearly=0A=
#    labeled as unofficial distributions.  Modifications which do not=0A=
#    carry the name Zope may be packaged in any form, as long as they=0A=
#    conform to all of the clauses above.=0A=
# =0A=
# =0A=
# Disclaimer=0A=
# =0A=
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY=0A=
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=0A=
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR=0A=
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS=0A=
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,=0A=
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT=0A=
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF=0A=
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND=0A=
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,=0A=
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT=0A=
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF=0A=
#   SUCH DAMAGE.=0A=
# =0A=
# =0A=
# This software consists of contributions made by Digital Creations and=0A=
# many individuals on behalf of Digital Creations.  Specific=0A=
# attributions are listed in the accompanying credits file.=0A=
# =0A=
#########################################################################=
#####=0A=
"""Access control package"""=0A=
=0A=
__version__=3D'$Revision: 1.110.4.10 $'[11:-2]=0A=
=0A=
import Globals, socket, regex, SpecialUsers=0A=
from Globals import HTMLFile, MessageDialog, Persistent, =
PersistentMapping=0A=
from string import join,strip,split,lower=0A=
from App.Management import Navigation, Tabs=0A=
from Acquisition import Implicit=0A=
from OFS.SimpleItem import Item=0A=
from base64 import decodestring=0A=
from App.ImageFile import ImageFile=0A=
from Role import RoleManager=0A=
from string import split, join, upper=0A=
from PermissionRole import _what_not_even_god_should_do, =
rolesForPermissionOn=0A=
from AuthEncoding import pw_validate=0A=
=0A=
ListType=3Dtype([])=0A=
NotImplemented=3D'NotImplemented'=0A=
=0A=
_marker=3D[]=0A=
=0A=
class BasicUser(Implicit):=0A=
    """Base class for all User objects"""=0A=
=0A=
    # ----------------------------=0A=
    # Public User object interface=0A=
    # ----------------------------=0A=
    =0A=
    # Maybe allow access to unprotected attributes. Note that this is=0A=
    # temporary to avoid exposing information but without breaking=0A=
    # everyone's current code. In the future the security will be=0A=
    # clamped down and permission-protected here. Because there are a=0A=
    # fair number of user object types out there, this method denies=0A=
    # access to names that are private parts of the standard User=0A=
    # interface or implementation only. The other approach (only=0A=
    # allowing access to public names in the User interface) would=0A=
    # probably break a lot of other User implementations with extended=0A=
    # functionality that we cant anticipate from the base scaffolding.=0A=
    def __allow_access_to_unprotected_subobjects__(self, name, =
value=3DNone):=0A=
        deny_names=3D('name', '__', 'roles', 'domains', '_getPassword',=0A=
                    'authenticate', '_shared_roles')=0A=
        if name in deny_names:=0A=
            return 0=0A=
        return 1=0A=
        =0A=
    def __init__(self,name,password,roles,domains):=0A=
        raise NotImplemented=0A=
=0A=
    def getUserName(self):=0A=
        """Return the username of a user"""=0A=
        raise NotImplemented=0A=
=0A=
    def getId(self):=0A=
        """Get the ID of the user. The ID can be used, at least from=0A=
        Python, to get the user from the user's=0A=
        UserDatabase"""=0A=
        return self.getUserName()        =0A=
=0A=
    def _getPassword(self):=0A=
        """Return the password of the user."""=0A=
        raise NotImplemented=0A=
=0A=
    def getRoles(self):=0A=
        """Return the list of roles assigned to a user."""=0A=
        raise NotImplemented=0A=
=0A=
    def getRolesInContext(self, object):=0A=
        """Return the list of roles assigned to the user,=0A=
           including local roles assigned in context of=0A=
           the passed in object."""=0A=
        name=3Dself.getUserName()=0A=
        roles=3Dself.getRoles()=0A=
        local=3D{}=0A=
        object=3Dgetattr(object, 'aq_inner', object)=0A=
        while 1:=0A=
            local_roles =3D getattr(object, '__ac_local_roles__', None)=0A=
            if local_roles:=0A=
                if callable(local_roles):=0A=
                    local_roles=3Dlocal_roles()=0A=
                dict=3Dlocal_roles or {}=0A=
                for r in dict.get(name, []):=0A=
                    local[r]=3D1=0A=
            inner =3D getattr(object, 'aq_inner', object)=0A=
            parent =3D getattr(inner, 'aq_parent', None)=0A=
            if parent is not None:=0A=
                object =3D parent=0A=
                continue=0A=
            if hasattr(object, 'im_self'):=0A=
                object=3Dobject.im_self=0A=
                object=3Dgetattr(object, 'aq_inner', object)=0A=
                continue=0A=
            break=0A=
        roles=3Dlist(roles) + local.keys()=0A=
        return roles=0A=
=0A=
    def getDomains(self):=0A=
        """Return the list of domain restrictions for a user"""=0A=
        raise NotImplemented=0A=
=0A=
    # ------------------------------=0A=
    # Internal User object interface=0A=
    # ------------------------------=0A=
    =0A=
    def authenticate(self, password, request):=0A=
        passwrd=3Dself._getPassword()=0A=
        result =3D pw_validate(passwrd, password)    =0A=
        domains=3Dself.getDomains()=0A=
        if domains:=0A=
            return result and domainSpecMatch(domains, request)=0A=
        return result=0A=
=0A=
    =0A=
    def _shared_roles(self, parent):=0A=
        r=3D[]=0A=
        while 1:=0A=
            if hasattr(parent,'__roles__'):=0A=
                roles=3Dparent.__roles__=0A=
                if roles is None: return 'Anonymous',=0A=
                if 'Shared' in roles:=0A=
                    roles=3Dlist(roles)=0A=
                    roles.remove('Shared')=0A=
                    r=3Dr+roles=0A=
                else:=0A=
                    try: return r+list(roles)=0A=
                    except: return r=0A=
            if hasattr(parent, 'aq_parent'):=0A=
                while hasattr(parent.aq_self,'aq_self'):=0A=
                    parent=3Dparent.aq_self=0A=
                parent=3Dparent.aq_parent=0A=
            else: return r=0A=
=0A=
    def allowed(self, parent, roles=3DNone):=0A=
        """Check whether the user has access to parent, assuming that=0A=
           parent.__roles__ is the given roles."""=0A=
        if roles is None or 'Anonymous' in roles:=0A=
            return 1=0A=
        usr_roles=3Dself.getRolesInContext(parent)=0A=
        for role in roles:=0A=
            if role in usr_roles:=0A=
                if (hasattr(self,'aq_parent') and=0A=
                    hasattr(self.aq_parent,'aq_parent')):=0A=
                    if parent is None: return 1=0A=
                    if (not hasattr(parent, 'aq_inContextOf') and=0A=
                        hasattr(parent, 'im_self')):=0A=
                        # This is a method, grab it's self.=0A=
                        parent=3Dparent.im_self=0A=
                    if not =
parent.aq_inContextOf(self.aq_parent.aq_parent,1):=0A=
                        if 'Shared' in roles:=0A=
                            # Damn, old role setting. Waaa=0A=
                            roles=3Dself._shared_roles(parent)=0A=
                            if 'Anonymous' in roles: return 1=0A=
                        return None=0A=
                return 1=0A=
=0A=
        if 'Shared' in roles:=0A=
            # Damn, old role setting. Waaa=0A=
            roles=3Dself._shared_roles(parent)=0A=
            if roles is None or 'Anonymous' in roles: return 1=0A=
            while 'Shared' in roles: roles.remove('Shared')=0A=
            return self.allowed(parent,roles)=0A=
=0A=
        return None=0A=
=0A=
    hasRole=3Dallowed=0A=
    domains=3D[]=0A=
    =0A=
    def has_role(self, roles, object=3DNone):=0A=
        """Check to see if a user has a given role or roles."""=0A=
        if type(roles)=3D=3Dtype('s'):=0A=
            roles=3D[roles]=0A=
        if object is not None:=0A=
            user_roles =3D self.getRolesInContext(object)=0A=
        else:=0A=
            # Global roles only...=0A=
            user_roles=3Dself.getRoles()=0A=
        for role in roles:=0A=
            if role in user_roles:=0A=
                return 1=0A=
        return 0=0A=
=0A=
    def has_permission(self, permission, object):=0A=
        """Check to see if a user has a given permission on an object."""=0A=
        roles=3DrolesForPermissionOn(permission, object)=0A=
        return self.has_role(roles, object)=0A=
=0A=
    def __len__(self): return 1=0A=
    def __str__(self): return self.getUserName()=0A=
    __repr__=3D__str__=0A=
=0A=
=0A=
class SimpleUser(BasicUser):=0A=
    """A very simple user implementation=0A=
=0A=
    that doesn't make a database commitment"""=0A=
=0A=
    def __init__(self,name,password,roles,domains):=0A=
        self.name   =3Dname=0A=
        self.__     =3Dpassword=0A=
        self.roles  =3Droles=0A=
        self.domains=3Ddomains=0A=
=0A=
    def getUserName(self):=0A=
        """Return the username of a user"""=0A=
        return self.name=0A=
=0A=
    def _getPassword(self):=0A=
        """Return the password of the user."""=0A=
        return self.__=0A=
=0A=
    def getRoles(self):=0A=
        """Return the list of roles assigned to a user."""=0A=
        return tuple(self.roles)=0A=
=0A=
    def getDomains(self):=0A=
        """Return the list of domain restrictions for a user"""=0A=
        return tuple(self.domains)=0A=
=0A=
class SpecialUser(SimpleUser):=0A=
    """Class for special users, like super and nobody"""=0A=
    def getId(self): pass=0A=
=0A=
class User(SimpleUser, Persistent):=0A=
    """Standard User object"""=0A=
=0A=
class Super(SpecialUser):=0A=
    """Super user=0A=
    """=0A=
    def allowed(self,parent,roles=3DNone):=0A=
        return roles is not _what_not_even_god_should_do=0A=
=0A=
    hasRole=3Dallowed=0A=
=0A=
    def has_role(self, roles, object=3DNone): return 1=0A=
=0A=
    def has_permission(self, permission, object): return 1=0A=
=0A=
_remote_user_mode=3D0=0A=
try:=0A=
    f=3Dopen('%s/access' % INSTANCE_HOME, 'r')=0A=
except IOError:=0A=
    raise 'InstallError', (=0A=
        'No access file found at %s - see INSTALL.txt' % INSTANCE_HOME=0A=
        )=0A=
try:=0A=
    data=3Dsplit(strip(f.readline()),':')=0A=
    f.close()=0A=
    _remote_user_mode=3Dnot data[1]=0A=
    try:    ds=3Dsplit(data[2], ' ')=0A=
    except: ds=3D[]=0A=
    super=3DSuper(data[0],data[1],('manage',), ds)=0A=
    del data=0A=
except:=0A=
    raise 'InstallError', 'Invalid format for access file - see =
INSTALL.txt'=0A=
=0A=
=0A=
nobody=3DSpecialUser('Anonymous User','',('Anonymous',), [])=0A=
system=3DSuper('System Processes','',('manage',), [])=0A=
=0A=
# stuff these in a handier place for importing=0A=
SpecialUsers.nobody=3Dnobody=0A=
SpecialUsers.system=3Dsystem=0A=
SpecialUsers.super=3Dsuper=0A=
=0A=
=0A=
class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, =
RoleManager,=0A=
                      Item):=0A=
    """Base class for UserFolder-like objects"""=0A=
=0A=
    meta_type=3D'User Folder'=0A=
    id       =3D'acl_users'=0A=
    title    =3D'User Folder'=0A=
=0A=
    isPrincipiaFolderish=3D1=0A=
    isAUserFolder=3D1=0A=
=0A=
    manage_options=3D(=0A=
        (=0A=
        {'label':'Contents', 'action':'manage_main',=0A=
         'help':('OFSP','User-Folder_Contents.stx')},=0A=
        )=0A=
        +RoleManager.manage_options=0A=
        +Item.manage_options=0A=
        )=0A=
=0A=
    __ac_permissions__=3D(=0A=
        ('Manage users',=0A=
         ('manage_users','getUserNames','getUser','getUsers',=0A=
          )=0A=
         ),=0A=
        )=0A=
=0A=
=0A=
    # ----------------------------------=0A=
    # Public UserFolder object interface=0A=
    # ----------------------------------=0A=
    =0A=
    def getUserNames(self):=0A=
        """Return a list of usernames"""=0A=
        raise NotImplemented=0A=
=0A=
    def getUsers(self):=0A=
        """Return a list of user objects"""=0A=
        raise NotImplemented=0A=
=0A=
    def getUser(self, name):=0A=
        """Return the named user object or None"""=0A=
        raise NotImplemented=0A=
=0A=
    def getUserById(self, id, default=3D_marker):=0A=
        """Return the user corresponding to the given id.=0A=
        """=0A=
        try: return self.getUser(id)=0A=
        except:=0A=
           if default is _marker: raise=0A=
           return default=0A=
=0A=
    def _doAddUser(self, name, password, roles, domains):=0A=
        """Create a new user"""=0A=
        raise NotImplemented=0A=
=0A=
    def _doChangeUser(self, name, password, roles, domains):=0A=
        """Modify an existing user"""=0A=
        raise NotImplemented=0A=
=0A=
    def _doDelUsers(self, names):=0A=
        """Delete one or more users"""=0A=
        raise NotImplemented=0A=
=0A=
=0A=
    # -----------------------------------=0A=
    # Private UserFolder object interface=0A=
    # -----------------------------------=0A=
=0A=
=0A=
    _remote_user_mode=3D_remote_user_mode=0A=
    _super=3Dsuper=0A=
    _nobody=3Dnobody=0A=
            =0A=
    def validate(self,request,auth=3D'',roles=3DNone):=0A=
=0A=
        if roles is _what_not_even_god_should_do:=0A=
            request.response.notFoundError()=0A=
        =0A=
        parents=3Drequest.get('PARENTS', [])=0A=
        if not parents:=0A=
            parent=3Dself.aq_parent=0A=
        else: parent=3Dparents[0]=0A=
=0A=
        if not auth:=0A=
            for ob in self.getUsers():=0A=
                domains=3Dob.getDomains()=0A=
                if domains:=0A=
                    if ob.authenticate('', request):=0A=
                        if ob.allowed(parent, roles):=0A=
                            ob=3Dob.__of__(self)=0A=
                            return ob=0A=
            nobody=3Dself._nobody=0A=
            if self._isTop() and nobody.allowed(parent, roles):=0A=
                ob=3Dnobody.__of__(self)=0A=
                return ob=0A=
            return None=0A=
=0A=
        # Only do basic authentication=0A=
        if lower(auth[:6])!=3D'basic ':=0A=
            return None=0A=
        name,password=3Dtuple(split(decodestring(split(auth)[-1]), ':', =
1))=0A=
=0A=
        # Check for superuser=0A=
        super=3Dself._super=0A=
        if self._isTop() and (name=3D=3Dsuper.getUserName()) and \=0A=
        super.authenticate(password, request):=0A=
            return super=0A=
=0A=
        # Try to get user=0A=
        user=3Dself.getUser(name)=0A=
        if user is None:=0A=
=0A=
            # If the user was not found and we are the top level user=0A=
            # database and the Anonymous user is allowed to access the=0A=
            # requested object, return the Anonymous user.=0A=
            if self._isTop() and self._nobody.allowed(parent, roles):=0A=
                user=3Dself._nobody.__of__(self)=0A=
                return user=0A=
=0A=
            # Otherwise, return None which will defer to higher level =
user=0A=
            # databases or cause an unauthorized to be raised in the=0A=
            # publisher layer.=0A=
            return None=0A=
=0A=
        # Try to authenticate the user=0A=
        if not user.authenticate(password, request):=0A=
=0A=
            # If no user was authenticated and we are the top level user=0A=
            # database and the Anonymous user is allowed to access the=0A=
            # requested object, return the Anonymous user.=0A=
            if self._isTop() and self._nobody.allowed(parent, roles):=0A=
                user=3Dself._nobody.__of__(self)=0A=
                return user=0A=
=0A=
            # Otherwise, return None which will defer to higher level =
user=0A=
            # databases or cause an unauthorized to be raised in the=0A=
            # publisher layer.=0A=
            return None=0A=
=0A=
        # We need the user to be able to acquire!=0A=
        user=3Duser.__of__(self)=0A=
=0A=
        # Try to authorize user=0A=
        if user.allowed(parent, roles):=0A=
            return user=0A=
=0A=
        return None=0A=
=0A=
=0A=
    if _remote_user_mode:=0A=
        =0A=
        def validate(self,request,auth=3D'',roles=3DNone):=0A=
            parent=3Drequest['PARENTS'][0]=0A=
            e=3Drequest.environ=0A=
            if e.has_key('REMOTE_USER'):=0A=
                name=3De['REMOTE_USER']=0A=
            else:=0A=
                for ob in self.getUsers():=0A=
                    domains=3Dob.getDomains()=0A=
                    if domains:=0A=
                        if ob.authenticate('', request):=0A=
                            if ob.allowed(parent, roles):=0A=
                                ob=3Dob.__of__(self)=0A=
                                return ob=0A=
                nobody=3Dself._nobody=0A=
                if self._isTop() and nobody.allowed(parent, roles):=0A=
                    ob=3Dnobody.__of__(self)=0A=
                    return ob=0A=
                return None=0A=
=0A=
            # Check for superuser=0A=
            super=3Dself._super=0A=
            if self._isTop() and (name=3D=3Dsuper.getUserName()):=0A=
                return super=0A=
=0A=
            # Try to get user=0A=
            user=3Dself.getUser(name)=0A=
            if user is None:=0A=
                return None=0A=
=0A=
            # We need the user to be able to acquire!=0A=
            user=3Duser.__of__(self)=0A=
=0A=
            # Try to authorize user=0A=
            if user.allowed(parent, roles):=0A=
                return user=0A=
            return None=0A=
=0A=
=0A=
    def _isTop(self):=0A=
        try: return =
self.aq_parent.aq_base.isTopLevelPrincipiaApplicationObject=0A=
        except: return 0=0A=
=0A=
    def __len__(self):=0A=
        return 1=0A=
=0A=
    _mainUser=3DHTMLFile('mainUser', globals())=0A=
    _add_User=3DHTMLFile('addUser', globals(),=0A=
                       remote_user_mode__=3D_remote_user_mode)=0A=
    _editUser=3DHTMLFile('editUser', globals(),=0A=
                       remote_user_mode__=3D_remote_user_mode)=0A=
    manage=3Dmanage_main=3D_mainUser=0A=
=0A=
    def domainSpecValidate(self, spec):=0A=
        for ob in spec:=0A=
            sz=3Dlen(ob)=0A=
            if not ((addr_match(ob) =3D=3D sz) or (host_match(ob) =3D=3D =
sz)):=0A=
                return 0=0A=
        return 1=0A=
=0A=
    def =
_addUser(self,name,password,confirm,roles,domains,REQUEST=3DNone):=0A=
        if not name:=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'A username must be specified',=0A=
                   action =3D'manage_main')=0A=
        if not password or not confirm:=0A=
            if not domains:=0A=
                return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'Password and confirmation must be =
specified',=0A=
                   action =3D'manage_main')=0A=
        if self.getUser(name) or (name=3D=3Dself._super.getUserName()):=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'A user with the specified name already =
exists',=0A=
                   action =3D'manage_main')=0A=
        if (password or confirm) and (password !=3D confirm):=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'Password and confirmation do not match',=0A=
                   action =3D'manage_main')=0A=
        =0A=
        if not roles: roles=3D[]=0A=
        if not domains: domains=3D[]=0A=
=0A=
        if domains and not self.domainSpecValidate(domains):=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'Illegal domain specification',=0A=
                   action =3D'manage_main')=0A=
        self._doAddUser(name, password, roles, domains)        =0A=
        if REQUEST: return self._mainUser(self, REQUEST)=0A=
=0A=
=0A=
    def =
_changeUser(self,name,password,confirm,roles,domains,REQUEST=3DNone):=0A=
        if password =3D=3D 'password' and confirm =3D=3D 'confirm':=0A=
            # Protocol for editUser.dtml to indicate unchanged password=0A=
            password =3D confirm =3D None=0A=
        if not name:=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'A username must be specified',=0A=
                   action =3D'manage_main')=0A=
        if password =3D=3D confirm =3D=3D '':=0A=
            if not domains:=0A=
                return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'Password and confirmation must be =
specified',=0A=
                   action =3D'manage_main')=0A=
        if not self.getUser(name):=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'Unknown user',=0A=
                   action =3D'manage_main')=0A=
        if (password or confirm) and (password !=3D confirm):=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'Password and confirmation do not match',=0A=
                   action =3D'manage_main')=0A=
=0A=
        if not roles: roles=3D[]=0A=
        if not domains: domains=3D[]=0A=
=0A=
        if domains and not self.domainSpecValidate(domains):=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'Illegal domain specification',=0A=
                   action =3D'manage_main')=0A=
        self._doChangeUser(name, password, roles, domains)=0A=
        if REQUEST: return self._mainUser(self, REQUEST)=0A=
=0A=
    def _delUsers(self,names,REQUEST=3DNone):=0A=
        if not names:=0A=
            return MessageDialog(=0A=
                   title  =3D'Illegal value', =0A=
                   message=3D'No users specified',=0A=
                   action =3D'manage_main')=0A=
        self._doDelUsers(names)=0A=
        if REQUEST: return self._mainUser(self, REQUEST)=0A=
=0A=
    def manage_users(self,submit=3DNone,REQUEST=3DNone,RESPONSE=3DNone):=0A=
        """ """=0A=
        if submit=3D=3D'Add...':=0A=
            return self._add_User(self, REQUEST)=0A=
=0A=
        if submit=3D=3D'Edit':=0A=
            try:    user=3Dself.getUser(reqattr(REQUEST, 'name'))=0A=
            except: return MessageDialog(=0A=
                    title  =3D'Illegal value',=0A=
                    message=3D'The specified user does not exist',=0A=
                    action =3D'manage_main')=0A=
            return =
self._editUser(self,REQUEST,user=3Duser,password=3Duser.__)=0A=
=0A=
        if submit=3D=3D'Add':=0A=
            name    =3Dreqattr(REQUEST, 'name')=0A=
            password=3Dreqattr(REQUEST, 'password')=0A=
            confirm =3Dreqattr(REQUEST, 'confirm')=0A=
            roles   =3Dreqattr(REQUEST, 'roles')=0A=
            domains =3Dreqattr(REQUEST, 'domains')=0A=
            return =
self._addUser(name,password,confirm,roles,domains,REQUEST)=0A=
=0A=
        if submit=3D=3D'Change':=0A=
            name    =3Dreqattr(REQUEST, 'name')=0A=
            password=3Dreqattr(REQUEST, 'password')=0A=
            confirm =3Dreqattr(REQUEST, 'confirm')=0A=
            roles   =3Dreqattr(REQUEST, 'roles')=0A=
            domains =3Dreqattr(REQUEST, 'domains')=0A=
            return self._changeUser(name,password,confirm,roles,=0A=
                                    domains,REQUEST)=0A=
=0A=
        if submit=3D=3D'Delete':=0A=
            names=3Dreqattr(REQUEST, 'names')=0A=
            return self._delUsers(names,REQUEST)=0A=
=0A=
        return self._mainUser(self, REQUEST)=0A=
=0A=
    def user_names(self):=0A=
        return self.getUserNames()=0A=
=0A=
    def manage_beforeDelete(self, item, container):=0A=
        if item is self:=0A=
            try: del container.__allow_groups__=0A=
            except: pass=0A=
=0A=
    def manage_afterAdd(self, item, container):=0A=
        if item is self:=0A=
            if hasattr(self, 'aq_base'): self=3Dself.aq_base=0A=
            container.__allow_groups__=3Dself=0A=
=0A=
    def __creatable_by_super__(self): return 1=0A=
=0A=
    def _setId(self, id):=0A=
        if id !=3D self.id:=0A=
            raise Globals.MessageDialog(=0A=
                title=3D'Invalid Id',=0A=
                message=3D'Cannot change the id of a UserFolder',=0A=
                action =3D'./manage_main',)=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
class UserFolder(BasicUserFolder):=0A=
    """Standard UserFolder object=0A=
=0A=
    A UserFolder holds User objects which contain information=0A=
    about users including name, password domain, and roles.=0A=
    UserFolders function chiefly to control access by authenticating=0A=
    users and binding them to a collection of roles."""=0A=
=0A=
    meta_type=3D'User Folder'=0A=
    id       =3D'acl_users'=0A=
    title    =3D'User Folder'=0A=
    icon     =3D'p_/UserFolder'=0A=
=0A=
    def __init__(self):=0A=
        self.data=3DPersistentMapping()=0A=
=0A=
    def getUserNames(self):=0A=
        """Return a list of usernames"""=0A=
        names=3Dself.data.keys()=0A=
        names.sort()=0A=
        return names=0A=
=0A=
    def getUsers(self):=0A=
        """Return a list of user objects"""=0A=
        data=3Dself.data=0A=
        names=3Ddata.keys()=0A=
        names.sort()=0A=
        users=3D[]=0A=
        f=3Dusers.append=0A=
        for n in names:=0A=
            f(data[n])=0A=
        return users=0A=
=0A=
    def getUser(self, name):=0A=
        """Return the named user object or None"""=0A=
        return self.data.get(name, None)=0A=
=0A=
    def _doAddUser(self, name, password, roles, domains):=0A=
        """Create a new user"""=0A=
        self.data[name]=3DUser(name,password,roles,domains)=0A=
=0A=
    def _doChangeUser(self, name, password, roles, domains):=0A=
        user=3Dself.data[name]=0A=
        if password is not None:=0A=
            user.__=3Dpassword=0A=
        user.roles=3Droles=0A=
        user.domains=3Ddomains=0A=
=0A=
    def _doDelUsers(self, names):=0A=
        for name in names:=0A=
            del self.data[name]=0A=
=0A=
=0A=
Globals.default__class_init__(UserFolder)=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
=0A=
def manage_addUserFolder(self,dtself=3DNone,REQUEST=3DNone,**ignored):=0A=
    """ """=0A=
    f=3DUserFolder()=0A=
    self=3Dself.this()=0A=
    try:    self._setObject('acl_users', f)=0A=
    except: return MessageDialog(=0A=
                   title  =3D'Item Exists',=0A=
                   message=3D'This object already contains a User =
Folder',=0A=
                   action =3D'%s/manage_main' % REQUEST['URL1'])=0A=
    self.__allow_groups__=3Df=0A=
    if REQUEST is not None:=0A=
        REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')=0A=
=0A=
=0A=
def rolejoin(roles, other):=0A=
    dict=3D{}=0A=
    for role in roles:=0A=
        dict[role]=3D1=0A=
    for role in other:=0A=
        dict[role]=3D1=0A=
    roles=3Ddict.keys()=0A=
    roles.sort()=0A=
    return roles=0A=
=0A=
addr_match=3Dregex.compile('[0-9\.\*]*').match #TS=0A=
host_match=3Dregex.compile('[-A-Za-z0-9\.\*]*').match #TS=0A=
=0A=
=0A=
def domainSpecMatch(spec, request):=0A=
    host=3D''=0A=
    addr=3D''=0A=
=0A=
    if request.has_key('REMOTE_HOST'):=0A=
        host=3Drequest['REMOTE_HOST']=0A=
=0A=
    if request.has_key('REMOTE_ADDR'):=0A=
        addr=3Drequest['REMOTE_ADDR']=0A=
=0A=
    if not host and not addr:=0A=
        return 0=0A=
=0A=
    if not host:=0A=
        try:    host=3Dsocket.gethostbyaddr(addr)[0]=0A=
        except: pass=0A=
    if not addr:=0A=
        try:    addr=3Dsocket.gethostbyname(host)=0A=
        except: pass=0A=
=0A=
    _host=3Dsplit(host, '.')=0A=
    _addr=3Dsplit(addr, '.')=0A=
    _hlen=3Dlen(_host)=0A=
    _alen=3Dlen(_addr)=0A=
    =0A=
    for ob in spec:=0A=
        sz=3Dlen(ob)=0A=
        _ob=3Dsplit(ob, '.')=0A=
        _sz=3Dlen(_ob)=0A=
=0A=
        if addr_match(ob)=3D=3Dsz:=0A=
            fail=3D0=0A=
            for i in range(_sz):=0A=
                a=3D_addr[i]=0A=
                o=3D_ob[i]=0A=
                if (o !=3D a) and (o !=3D '*'):=0A=
                    fail=3D1=0A=
                    break=0A=
            if fail:=0A=
                continue=0A=
            return 1=0A=
=0A=
        if host_match(ob)=3D=3Dsz:=0A=
            if _hlen < _sz:=0A=
                continue=0A=
            elif _hlen > _sz:=0A=
                _item=3D_host[-_sz:]=0A=
            else:=0A=
                _item=3D_host=0A=
            fail=3D0=0A=
            for i in range(_sz):=0A=
                h=3D_item[i]=0A=
                o=3D_ob[i]=0A=
                if (o !=3D h) and (o !=3D '*'):=0A=
                    fail=3D1=0A=
                    break=0A=
            if fail:=0A=
                continue=0A=
            return 1=0A=
    return 0=0A=
=0A=
=0A=
def absattr(attr):=0A=
    if callable(attr): return attr()=0A=
    return attr=0A=
=0A=
def reqattr(request, attr):=0A=
    try:    return request[attr]=0A=
    except: return None=0A=

------=_NextPart_000_0021_01C080A0.1469E1E0--