Twisted authentication cread problem
I have error in pb, cred...
We have a simple client:
#!/usr/bin/env python
from twisted.spread import pb
from twisted.internet import reactor
from twisted.cred import credentials
def main():
factory = pb.PBClientFactory()
reactor.connectTCP("localhost", 8801, factory)
def1 = factory.login(credentials.UsernamePassword("admin", "pass2"))
def1.addCallback(connected)
def1.addErrback(bad_connected)
def1.addBoth(disconnect)
reactor.run()
def bad_connected(perspective):
print 'bad login or password', perspective
perspective.addCallback(disconnect)
def connected(perspective):
print "got perspective1 ref:", perspective
print "asking it to foo(13)"
return perspective.callRemote("foo", 13)
def disconnect(perspective):
print 'disconnect'
reactor.stop()
main()
If we connect -> perspective.callRemote("foo", 13) and Disconnect
If we no connect -> print 'bad login or password' and Disconnect
sever code
#!/usr/bin/env python
from zope.interface import implements
from twisted.python import failure, log
from twisted.cred import portal, checkers, credentials, error as credError
from twisted.internet import defer, reactor
from twisted.spread import pb
class PasswordDictChecker:
implements(checkers.ICredentialsChecker)
credentialInterfaces = (credentials.IUsernamePassword,)
def __init__(self, passwords):
"passwords: a dict-like object mapping usernames to passwords"
self.passwords = passwords
def requestAvatarId(self, credentials):
username = credentials.username
if self.passwords.has_key(username):
if credentials.password == self.passwords[username]:
return defer.succeed(username)
else:
开发者_如何学Go return defer.fail(
credError.UnauthorizedLogin("Bad password"))
else:
return defer.fail(
credError.UnauthorizedLogin("No such user"))
class MyRealm(object):
implements(portal.IRealm)
def requestAvatar(self, user, mind, *interfaces):
assert pb.IPerspective in interfaces
avatar = MyAvatar(user)
avatar.attached(mind)
return pb.IPerspective, avatar, lambda a=avatar:a.detached(mind)
class MyAvatar(pb.Avatar):
def __init__(self, user):
self.user = user
def attached(self, mind):
self.remote = mind
print 'User %s connected' % (self.user,)
def detached(self, mind):
self.remote = None
print 'User %s disconnected' % (self.user,)
passwords = {
'admin': 'aaa',
'user1': 'bbb',
'user2': 'ccc'
}
if __name__ == "__main__":
checker = PasswordDictChecker(passwords)
realm = MyRealm()
p = portal.Portal(realm, [checker])
reactor.listenTCP(8801, pb.PBServerFactory(p))
reactor.run()
The problem is that with this writing displays an error:
Unhandled Error
Traceback (most recent call last):
Failure: twisted.cred.error.UnhandledCredentials: No checker for twisted.cred.credentials.IUsernameHashedPassword, twisted.spread.pb.IUsernameMD5Password, twisted.spread.interfaces.IJellyable
Why should he IUsernameHashedPassword? If i change to
credentialInterfaces = (credentials.IUsernamePassword, redentials.IUsernameHashedPassword)
Code is executed on but died on string:
if credentials.password == self.passwords[username]:
Unhandled Error
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\twisted\spread\pb.py", line 841, in _recvMessage
netResult = object.remoteMessageReceived(self, message, netArgs, netKw)
File "C:\Python27\lib\site-packages\twisted\spread\flavors.py", line 114, in remoteMessageReceived
state = method(*args, **kw)
File "C:\Python27\lib\site-packages\twisted\spread\pb.py", line 1347, in remote_respond
d = self.portal.login(self, mind, IPerspective)
File "C:\Python27\lib\site-packages\twisted\cred\portal.py", line 115, in login
return maybeDeferred(self.checkers[i].requestAvatarId, credentials
--- <exception caught here> ---
File "C:\Python27\lib\site-packages\twisted\internet\defer.py", line 133, in maybeDeferred
result = f(*args, **kw)
File "C:/Dropbox/my_py/network/pb-cred/pb6serverV2.py", line 21, in requestAvatarId
if credentials.password == self.passwords[username]:
exceptions.AttributeError: _PortalAuthChallenger instance has no attribute 'password'
Please help me understand the problem.
You need to use a twisted.spread.pb.IUsernameMD5Password
credentials object to log in, because Twisted's PB uses a little challenge/response scheme during authentication, which requires the password to be hashed (MD5). This algorithm is currently hard-coded in the PB module. You cannot easily implement/use other credential containers with PB, unless you are planning to roll your own authentication sub-protocol.
This protocol is intended to protect client and server against man-in-the-middle attacs.
I would recommend having a look at the source code of InMemoryUsernamePasswordDatabaseDontUse
for a description of how checkers are supposed to check the credentials handed to them (the name of that class is a subtle hint not to use the class in a production server...)
My simple test server use PB and MySQL
# -*- coding: utf-8 -*-
import MySQLdb
from twisted.cred import portal, checkers, credentials, error as credError
from twisted.protocols import basic
from twisted.internet import protocol, reactor, defer
from zope.interface import Interface, implements
from twisted.spread import pb
from twisted.enterprise import adbapi, util as dbutil
class MyPerspective(pb.Avatar):
def __init__(self, name):
self.name = name
def perspective_foo(self, arg):
print "I am", self.name, "perspective_foo(",arg,") called on", self
return arg
class MyRealm:
implements(portal.IRealm)
def requestAvatar(self, avatarId, mind, *interfaces):
#print 'qqqq', avatarId
if pb.IPerspective not in interfaces:
raise NotImplementedError
return pb.IPerspective, MyPerspective(avatarId), lambda:None
class DbPasswordChecker(object):
implements(checkers.ICredentialsChecker)
credentialInterfaces = (credentials.IUsernamePassword,
credentials.IUsernameHashedPassword)
def __init__(self, dbconn):
self.dbconn = dbconn
def requestAvatarId(self, credentials):
query = "select userid, password from user where username = %s" % (
dbutil.quote(credentials.username, "char"))
return self.dbconn.runQuery(query).addCallback(
self._gotQueryResults, credentials)
def _gotQueryResults(self, rows, userCredentials):
if rows:
userid, password = rows[0]
return defer.maybeDeferred(
userCredentials.checkPassword, password).addCallback(
self._checkedPassword, userid)
else:
raise credError.UnauthorizedLogin, "No such user"
def _checkedPassword(self, matched, userid):
if matched:
return userid
else:
raise credError.UnauthorizedLogin("Bad password")
DB_DRIVER = "MySQLdb"
DB_ARGS = {
'db': 'dbname',
'user': 'root',
'passwd': '',
}
connection = adbapi.ConnectionPool(DB_DRIVER, **DB_ARGS)
p = portal.Portal(MyRealm())
p.registerChecker(DbPasswordChecker(connection))
#p.registerChecker(PasswordDictChecker(passwords))
reactor.listenTCP(8800, pb.PBServerFactory(p))
reactor.run()
精彩评论