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