Jean-Paul,

Thanks for your answers. Answers bellow. Also attachments of
client/server application tests.

On Fri, 2010-02-12 at 20:06 +0000, exar...@twistedmatrix.com wrote:
> On 06:03 pm, r...@cttc.upc.edu wrote:
> >Hello everybody,
> >
> >I am trying to build a a client/server application using Perspective
> >Broker and wanting to authenticate against a PostgreSQL database.
> >Everything works fine if I user plain text passwords, but when trying 
> >to
> >hash then using md5 using
> 
> What do you mean when you say you're using plain text passwords? 
> Authentication involves multiple parties handling the password in 
> multiple ways, and the "plain text"-ness of the password changes from 
> step to step.

I mean that the the server authenticates the client using a NOT HASHED
password. In my case using a VARCHAR field in a PostgreSQL table

> >from hashlib import md5
> >md5Password = md5(password).hexdigest()
> >
> >then it does not authenticate (I use
> >credentials.checkMD5Password(password) at the checker class)
> >
> >Then after reading
> >
> >twisted/spread/pb.py
> >
> >I saw that everything is done in the functions:
> >
> >respond(challenge, password)
> >challenge()
> >
> >and the methods
> >
> >checkMD5Password(self, md5Password)
> >checkPassword(self, password)
> >
> >at the
> >
> >class _PortalAuthChallenger(Referenceable, _JellyableAvatarMixin)
> >
> >By changing digest() with hexdigest(), it works.
> >
> >The question is:
> >
> >I there some way to make it work without making changes at the 'pb.py'
> >module?
> >
> >Yes. I should use md5Password = md5(password).digest() to produce the
> >password, but then I cant authenticate with a 'pure-ftpd' daemon I need
> >to work with.
> >
> >Any alternatives?
> 
> You should register an IUsernameHashedPassword checker with the portal 
> you pass to PBServerFactory and use PBClientFactory.login.  See 
> pbbenchserver.py and pbbenchclient.py for examples of this.  Despite the 

Yes I did so. You can see the attached examples I am testing with

> fact that you're passing a UsernamePassword instance to 
> PBClientFactory.login, the plain text password is never sent over the 
> network.

Yes I Know. You do that at the 'respond(challenge, password)' in
'pb.py', do you?

> 
> Also, IUsernameMD5Password is about to be deprecated, along with the 
> checkMD5Password method of _PortalAuthChallenger.

So, how should I do it in order not to be using deprecated code? I would
like to know some details so that I can have a better understanding of
how authentication is working.


Jean-Paul:

To sum up. I would like to use md5 hashed password, so as the password
can not be read at the server, but as it is at a database table it is
not as terrible as if I where using a simple text file. Furthermore I am
having problems to use a python ftp client with ssl to connect to
'pure-ftpd' with TLS, and in this case, I am really sending password
clear-text over the wire even if using hashed passwords at the server.

Thanks again for your interest

Regards

> 
> Jean-Paul
> 
> _______________________________________________
> Twisted-Python mailing list
> Twisted-Python@twistedmatrix.com
> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
> 
-- 
Ramiro Alba

Centre Tecnològic de Tranferència de Calor
http://www.cttc.upc.edu


Escola Tècnica Superior d'Enginyeries
Industrial i Aeronàutica de Terrassa
Colom 11, E-08222, Terrassa, Barcelona, Spain
Tel: (+34) 93 739 86 46

-- 
Aquest missatge ha estat analitzat per MailScanner
a la cerca de virus i d'altres continguts perillosos,
i es considera que està net.

#!/usr/bin/python

from twisted.internet import ssl, reactor
from twisted.spread import pb
from twisted.cred.credentials import UsernamePassword

class DefinedError(pb.Error):
    pass

def success(message):
    print "Message received:",message
    reactor.stop()

def failure(error):
    t = error.trap(DefinedError)
    print "error received:", t
    reactor.stop()

def connected(perspective):
    perspective.callRemote('echo', "hello world").addCallbacks(success, failure)
    print "connected."

factory = pb.PBClientFactory()
reactor.connectSSL('localhost', 2323, factory, ssl.ClientContextFactory())
factory.login(UsernamePassword("raq", "diga33")).addCallbacks(connected, failure)
reactor.run()
#!/usr/bin/env python

from twisted.cred import error
from twisted.cred.credentials import IUsernameHashedPassword, IUsernamePassword
from twisted.cred.checkers import ICredentialsChecker
from twisted.internet.defer import Deferred
from twisted.python import log
from twisted.enterprise import adbapi
from twisted.cred.portal import Portal, IRealm
from twisted.spread import pb
from twisted.internet import reactor
from OpenSSL import SSL
  
from zope.interface import implements

import sys

class DBCredentialsChecker(object):
    implements(ICredentialsChecker)

    def __init__(self, dbConn):
        
	self.dbConn = dbConn
        self.credentialInterfaces = (IUsernamePassword, IUsernameHashedPassword,)

    def requestAvatarId(self, credentials):
	userName = str.strip(credentials.username)
	queryStr = "SELECT username, password FROM ruser WHERE username = '%s'" % userName
        dbDeferred = self.dbConn.runQuery(queryStr)
        deferred = Deferred()
        dbDeferred.addCallbacks(self._cbAuthenticate, self._ebAuthenticate,
				callbackArgs=(credentials, deferred),
				errbackArgs=(credentials, deferred))
        return deferred

    def _cbAuthenticate(self, result, credentials, deferred):
	if len(result) == 0:
	    deferred.errback(error.UnauthorizedLogin('Username unknown'))
        else:
            username, password = result[0]
	    username = username.strip()
	    password = password.strip()
	    if credentials.checkMD5Password(password):
		deferred.callback(credentials.username)
            else:
                deferred.errback(error.UnauthorizedLogin('Password mismatch'))
    def _ebAuthenticate(self, message, credentials, deferred):
        deferred.errback(error.LoginFailed(message))

class DefinedError(pb.Error):
    pass

class RqueueAvatar(pb.Avatar):

    def setUserInfo(self, userId, userName, fullName):
	self.userId = userId
	self.userName = userName
	self.fullName = fullName

    def perspective_userInfo(self):
	return (self.userId, self.userName, self.fullName)

    def perspective_getFile(self, fileName):
	file = open(fileName, "rb")
	return file.read()

    def perspective_sendFile(self, data, fileName):
	file = open("cp-" + fileName, "wb")
	file.write(data)
	file.close()
	return fileName

    def perspective_echo(self, text):
        print 'echoing', text
	message = "%s: %s" % (self.userName, text)
        return message

    def perspective_error(self):
        raise DefinedError("exception!")

    def logout(self):
        print "logged out"


class RqueueRealm:

    implements(IRealm)

    def __init__(self, dbConn):
	self.dbConn = dbConn

    def requestAvatar(self, avatarId, mind, *interfaces):
        if pb.IPerspective  in interfaces:
	    userName = avatarId
            userQuery = "SELECT ruser_id, username, fullname FROM ruser WHERE username = '%s'" % userName
            deferred = self.dbConn.runQuery(userQuery)
	    return deferred.addCallback(self._gotQueryResults)
        else:
            raise NotImplementedError("Only pb.IPerspective interface is supported by this realm")

    def _gotQueryResults(self, rows):
        userId, userName, fullName = rows[0]
	userName = userName.strip()
	fullName = fullName.strip()
        self._registerLogin(userId)
	avatar = RqueueAvatar()
	avatar.setUserInfo(userId, userName, fullName)
	return pb.IPerspective, avatar, avatar.logout
    
    def _registerLogin(self, avatarId):
        "Add counter and set login flag to the user entry"
        pass

class ServerContextFactory:
    
    def getContext(self):
        ctx = SSL.Context(SSL.SSLv23_METHOD)
	ctx.use_certificate_file('/etc/ssl/private/pure-ftpd.pem')
        ctx.use_privatekey_file('/etc/ssl/private/pure-ftpd.pem')
        return ctx


DB_DRIVER = "pyPgSQL.PgSQL"
DB_ARGS = {'database': 'cttc-rusers', 'user': 'postgres'}

def main():
    #log.startLogging(sys.stdout)

    connection = adbapi.ConnectionPool(DB_DRIVER, **DB_ARGS)
    realm = RqueueRealm(connection)
    checkers = (DBCredentialsChecker(connection),)
    portal = Portal(realm, checkers)
    reactor.listenSSL(2323, pb.PBServerFactory(portal), ServerContextFactory())

if __name__ == "__main__":
    reactor.callWhenRunning(main)
    reactor.run()

_______________________________________________
Twisted-Python mailing list
Twisted-Python@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to