sleekxmpp threaded authentication

2019-08-11 13:56发布

问题:

so... I have a simple chat client like so:

class ChatClient(sleekxmpp.ClientXMPP):
    def __init__(self, jid, password, server):
        sleekxmpp.ClientXMPP.__init__(self, jid, password, ssl=True)

        self.add_event_handler("session_start", self.start)

        self.register_plugin('xep_0030')
        self.register_plugin('xep_0004')
        self.register_plugin('xep_0060')
        self.register_plugin('xep_0199')

        self.ssl_version = ssl.PROTOCOL_SSLv3
        self.connected = self.connect()
        if self.connected:
            self.process(threaded=True)


    def start(self, event):
        self.send_presence(priority = "-9001")
        self.get_roster(blocking = True, timeout = 3)

    def message(self, targets, msg):
        for target in targets:
            self.send_message(target, msg)

and I have an "verify" function to make sure you input your username/pass right:

def authenticate(username, password, server):
    xmppuser = username + '@' + server
    passTester = ChatClient(xmppuser, password)

    passTester.disconnect(wait = True)
    authenticated = passTester.authenticated
    return authenticated

Now, the problem comes in where I have the chat client as threaded, I run into the situation where I try to check ChatClient.authenticated before the server had a chance to actually connect. As you can see, I tried to "wait" on the disconnect but there's nothing in the send queue so it disconnects right away.

An alternate I tried is this:

def authenticate(username, password, server):
    xmppuser = username + '@' + server
    passTester = ChatClient(xmppuser, password)

    passTester.message('bogusName', 'ladfhkjdglkhjdfg')
    passTester.disconnect(wait = True)
    authenticated = passTester.authenticated
    return authenticated

Now that I sent a bogus message the disconnect call has something to wait for. when I input a correct username/pass with this code, the disconnect waits for a message to get sent (which involves waiting for a real connection), sends nothing and ChatClient.authenticated is set to True!

Unfortunately, when I input a wrong username/pass the message never gets sent and the disconnect(wait=True) never disconnects as the message never gets sent.

Does anyone else have a more proper way to "authenticate"?

回答1:

This would be a good reason for changing the .authenticated and related fields to be threading.Event objects so that you could use wait() for situations like this, but I'm not sure how much that would break existing user code.

But short of modifying SleekXMPP, what you will need to do is wait for certain events to fire. For example, if your client successfully authenticated, then there will be a session_start event (I may add an auth_success or similar event later). Likewise, if authentication failed for a single mechanism, there will be a failed_auth event. If no authentication methods at all succeeded (which is what you'd be interested in), there will be a no_auth event.

So you can add handlers for these events, and have those handlers place a token in a queue, and then wait for the desired token to arrive.

class ChatClient(ClientXMPP):
    def __init__(self, ...):
        ...
        self.auth_queue = queue.Queue()
        self.add_event_handler('no_auth', self.failed)

    def start(self, event):
        self.auth_queue.put('success')
        ...

    def failed(self, event):
        self.auth_queue.put('failed')


def authenticate(username, password, server):
    xmppuser = username + '@' + server
    passTester = ChatClient(xmppuser, password)
    try:
        result = passTester.auth_queue.get(timeout=10)
    except queue.Empty:
        result = 'failed'
    passTester.disconnect()
    return result == 'success'

Don't forget that we also have the chat room at sleek@conference.jabber.org.

-- Lance



标签: python xmpp