[Zope-dev] Membership and latest LoginManager

Dan L. Pierson dan@sol.control.com
13 Nov 2000 13:37:05 -0500


I've been trying to get Membership 0.7.6 working with
LoginManager-0-8-8b1 (and it's associated ZPatterns) under Zope 2.2.2
on RedHat 6.2.  After probing around it seems that there is a problem
storing member passwords.  The  following trace from print statements
inserted in PersistentUserSource illustrates the problem:

==================================================================
    using crypt
encodePassword( testing , scheme=' CRYPT ', salt= U3 ) ==>
{CRYPT}U35nKDwqMBaD2addUser 
setting password for aral to "{CRYPT}U35nKDwqMBaD2"
   password = "{CRYPT}R0nzSkU8huehY"
setting again with direct assignment
   password = "{CRYPT}U35nKDwqMBaD2"
authenticateUser(self, aral , testing )
comparePassword( testing , {CRYPT}U35nKDwqMBaD2 )
    using crypt
encodePassword( testing , scheme=' CRYPT ', salt= U3 ) ==>
{CRYPT}U35nKDwqMBaD2
comparePassword ==> {CRYPT}U35nKDwqMBaD2 == {CRYPT}U35nKDwqMBaD2
passwords matched
==================================================================

Source bits with print statements follows at the end of this article.
The problem seems to be that:

 ...manage_changeProperties(password = new_value)

doesn't change the password correctly, but

 ...password = new_value

works.  

Does anyone know what's really going on here?

Modified from PersistentUserSource.py:PersistentUserSource:

    def authenticateUser(self,user,password,request):
        name = user.getUserName()
        ok=0
        print 'authenticateUser(self,',name,',',password,')'
        if self.cacheGetAuth(name, password):
            return 1
        if hasattr(self, 'userAuthenticate'):
            old_au = setuid(self.REQUEST, _LoggingInUser)
            try:
                ok = self.userAuthenticate(
                   self, request, user=user, password=password)
                if ok:
                    print 'self authenticated'
            finally:
                setuid(self.REQUEST, old_au)
        else:
            # Why does the following always return '{CRYPT}R0nzSkU8huehY' ???
            encpw =  user.propertysheets.SystemProperties.password
            print 'comparePassword(',password,',',encpw,')'
            ok = self.comparePassword(password, encpw)
            if ok:
                print 'passwords matched'
        
        if ok:
            self.cacheSetAuth(name, password)

        return ok

    def addUser(self, userid, password, roles, domains):
        user = self.newItem(userid)
        user.propertysheets.RestrictedProperties.manage_changeProperties(roles = roles)
        user.propertysheets.SystemProperties.manage_changeProperties(domains = domains)
        epass=self.encodePassword(password)
        # This always sets the password to '{CRYPT}R0nzSkU8huehY' !!!
        print 'addUser setting password for %s to "%s"' % (userid, epass)
        user.propertysheets.SystemProperties.manage_changeProperties(password = epass)
        print '   password = "%s"' % user.propertysheets.SystemProperties.password
        # This works - what is broken with the manage_changeProperties call?
        print 'setting again with direct assignment'
        user.propertysheets.SystemProperties.password = epass
        print '   password = "%s"' % user.propertysheets.SystemProperties.password
        return user

Modified from LoginManager/UserSources.py:BasicUserSource

    def encodePassword(self, text, scheme='CRYPT', salt=None):
        """Encode a password"""
        if scheme == 'CRYPT' and crypt is not None:
            print '    using crypt'
            if salt is None:
                salt = whrandom.randint(0, 2**12-1)
                salt = saltdict[salt >> 6] + saltdict[salt & 0x3f]
            pw = '{CRYPT}' + crypt.crypt(text, salt)
        elif scheme == 'SHA':
            pw = '{SHA}' + binascii.b2a_base64(sha.sha(text).digest())[:-1]
        elif scheme == 'SSHA':
            if salt is None:
                # XXX random salt selection could be much better...
                salt = hex(whrandom.randint(0, sys.maxint-1))[2:]
                salt = sha.sha(salt).digest()
            ssha = sha.sha(text + salt).digest()+salt
            pw = '{SSHA}' + binascii.b2a_base64(ssha)[:-1]
        else:
            pw = text

        print "encodePassword(",text,", scheme='",scheme,"', salt=",salt,") ==> ",pw
        return pw

    def comparePassword(self, text, pw):
        """Check if password matches"""

        salt = self.extractSalt(pw)
        if pw[0] == '{':
            scheme = split(pw[1:], '}', 1)[0]
        else:
            scheme = ''
        text = self.encodePassword(text, scheme, salt)
        print 'comparePassword ==>',text,'==',pw
        return (text == pw)