[Zope-dev] PATCH: Expanded "access" file

Phillip J. Eby pje@telecommunity.com
Sat, 22 Jul 2000 20:48:28 -0500


At 01:27 PM 7/19/00 -0500, Phillip J. Eby wrote:
>
>Hm.  I don't think this could be classed as a "minor" change, however,
>since it has impact on ownership, for example.  What's the path of the user
>folder which is above "/", for example?  The whole thing is useless if
>these extra users can't be owners, and the ownership machinery right now
>wants an access path.  I think perhaps we should go the fishbowl route on
>this, if only to make sure that Jim doesn't have a heart attack when he
>gets back.  :)

Looks like I was wrong.  This was in fact quite a minor patch.  I've only
tested this lightly so far, but if anyone else wants to try it out, here it
is.  Note that the new "access" file format looks like this:

# Lines beginning with '#' are comments
#
# First user in file is "super" user, unless roles
# are specified, in which case there is NO superuser
#
superusername:{SHA}fsjdflfs:domain1.com
#
# Format for all other users is name:pw:domains:roles
#
somemanager:{SHA}rr70flksf::Manager Editor SomeotherRole
somedeveloper:{CRYPT}flsdajfd:domain2.com:Manager

You can access a dictionary of all the "access" file users by importing
rootUsers from AccessControl.SpecialUsers.  It is a dictionary mapping user
names to user objects.  Be sure to use __of__ to wrap them to your
UserFolder if you are adding support for this to a UserFolder variant.  I
have not yet added support for this to LoginManager, but as you'll see from
the changes to the basic UserFolder, it is probably not going to be at all
difficult to do so.

Patch follows; watch out for line wrapping...

Index: User.py
===================================================================
RCS file: /cvs-repository/Zope2/lib/python/AccessControl/User.py,v
retrieving revision 1.112
diff -u -r1.112 User.py
--- User.py     2000/07/11 18:42:48     1.112
+++ User.py     2000/07/23 01:38:51
@@ -314,13 +314,30 @@
         'No access file found at %s - see INSTALL.txt' % INSTANCE_HOME

         )
 try:
-    data=split(strip(f.readline()),':')
-    f.close()
-    _remote_user_mode=not data[1]
-    try:    ds=split(data[2], ' ')
-    except: ds=[]
-    super=Super(data[0],data[1],('manage',), ds)
-    del data
+    d=f.readlines(); f.close(); del f
+    rootUsers = SpecialUsers.rootUsers = {}
+
+    for data in map(strip,d):
+       if not data or data[0]=='#': continue
+        data=split(data+':::',':')     # allow for missing fields
+
+        n = data[0]
+        ds = split(strip(data[2])) # space-delimited domains
+        pw = data[1]
+        r  = split(strip(data[3])) # space-delimited roles
+
+        if rootUsers or r:
+           # If not first user in file, or if roles are specified,
+            # user is a "normal" user object
+            rootUsers[n] =
SimpleUser(n,data[1],tuple(split(data[3])),data[2])
+        else:
+            super = rootUsers[n] = Super(n,pw,('manage',), ds)
+            _remote_user_mode=not pw
+
+        del data,n,ds,pw,r
+
+    del d
+
 except:
     raise 'InstallError', 'Invalid format for access file - see INSTALL.txt'
 
@@ -383,6 +400,11 @@
         """
         try: return self.getUser(id)
         except:
+
+           # Don't return the superuser, so that super can't own things
+           if rootUsers.has_key(id) and id!=super.getUserName():
+               return rootUsers[id].__of__(self)
+
            if default is _marker: raise
            return default
 
@@ -405,7 +427,6 @@
 
 
     _remote_user_mode=_remote_user_mode
-    _super=super
     _nobody=nobody
             
     def validate(self,request,auth='',roles=None):
@@ -440,11 +461,11 @@
             return None
         name,password=tuple(split(decodestring(split(auth)[-1]), ':', 1))
 
-        # Check for superuser
-        super=self._super
-        if self._isTop() and (name==super.getUserName()) and \
-        super.authenticate(password, request):
-            return super
+        # Check for superuser/root users
+        if self._isTop() and rootUsers.has_key(name):
+            user = rootUsers[name].__of__(self)
+            if user.authenticate(password, request):
+                return user
 
         # Try to get user
         user=self.getUser(name)
@@ -508,10 +529,9 @@
                     return ob
                 return None
 
-            # Check for superuser
-            super=self._super
-            if self._isTop() and (name==super.getUserName()):
-                return super
+            # Check for superuser/root users
+            if self._isTop() and rootUsers.has_key(name):
+                return rootUsers[name].__of__(self)
 
             # Try to get user
             user=self.getUser(name)
@@ -560,7 +580,7 @@
                    title  ='Illegal value', 
                    message='Password and confirmation must be specified',
                    action ='manage_main')
-        if self.getUser(name) or (name==self._super.getUserName()):
+        if self.getUser(name) or (rootUsers.has_key(name)):
             return MessageDialog(
                    title  ='Illegal value', 
                    message='A user with the specified name already exists',