扭曲的身份验证cread问题

时间:2011-07-20 18:24:13

标签: python twisted

我在pb中有错误,信用卡......

我们有一个简单的客户:

#!/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()

如果我们连接 - > perspective.callRemote(“foo”,13)和Disconnect

如果我们没有连接 - >打印'bad login or password'并断开连接

服务器代码

#!/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:
                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()

问题在于,写入时会显示错误:

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

他为什么要IUsernameHashedPassword? 如果我改为

 credentialInterfaces = (credentials.IUsernamePassword, redentials.IUsernameHashedPassword)

代码执行但在字符串上死亡:

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'

请帮我理解这个问题。

2 个答案:

答案 0 :(得分:2)

您需要使用twisted.spread.pb.IUsernameMD5Password凭据对象登录,因为Twisted的PB在身份验证期间使用了一些挑战/响应方案,这需要对密码进行哈希处理(MD5)。该算法目前在PB模块中进行了硬编码。您不能轻易地使用PB实现/使用其他凭据容器,除非您计划推出自己的身份验证子协议。

此协议旨在保护客户端和服务器免受中间人的影响。

我建议您查看InMemoryUsernamePasswordDatabaseDontUse的源代码,了解如何检查棋子应该检查传递给他们的凭据(该类的名称是一个微妙的提示,不使用该类中的生产服务器...)

答案 1 :(得分:0)

我的简单测试服务器使用PB和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()