xmppjs / xmpp.js

XMPP for JavaScript
ISC License
2.19k stars 374 forks source link

React Native: infinate loop when not-authorized #588

Closed DaveLomber closed 5 years ago

DaveLomber commented 5 years ago

I use the latest xmppjs lib under React Native

I implemented a custom auth function:


var XMPP = require('@xmpp/client')
var xmppClient = XMPP.client({
    service: Config.chatProtocol.websocket,
    credentials: function authenticate(auth, mechanism) {
        var crds = {
            username: cbUserName,
            password: cbUserPassword,
        }
        auth(crds)
    }
});

...

xmppClient.start();

Now I intentionally pass an invalid password for user and trying to connect.

2 observations from here: 1) I do not see a way on how to get a 'not-authorized' callback. Also, an 'error' callback never fires. 2) In infinate loop occurs, so it's trying to authenticate again and again Here is log:


15:15:42: [Chat] SENT: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADM1NTY4My0xMgBuZXdVc2VyQXdlc29tZQ==</auth>
15:15:42: [Chat] status opening 
15:15:42: [Chat] SENT: <open version="1.0" xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="chat.connectycube.com"/>
15:15:42: [Chat] RECV: <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
15:15:42: [Chat] RECV: <open xmlns='urn:ietf:params:xml:ns:xmpp-framing' from='chat.connectycube.com' id='5cd49981-f8dd-40c1-b273-2b788864e4be' version='1.0' xml:lang='en' />
15:15:42: [Chat] status open <open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="chat.connectycube.com" id="5cd49981-f8dd-40c1-b273-2b788864e4be" version="1.0" xml:lang="en"/>
15:15:42: [Chat] RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
15:15:42: [Chat] SENT: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADM1NTY4My0xMgBuZXdVc2VyQXdlc29tZQ==</auth>
15:15:42: [Chat] status opening 
15:15:42: [Chat] SENT: <open version="1.0" xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="chat.connectycube.com"/>
15:15:43: [Chat] RECV: <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
15:15:43: [Chat] RECV: <open xmlns='urn:ietf:params:xml:ns:xmpp-framing' from='chat.connectycube.com' id='5cd49981-f8dd-40c1-b273-2b788864e4be' version='1.0' xml:lang='en' />
15:15:43: [Chat] status open <open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="chat.connectycube.com" id="5cd49981-f8dd-40c1-b273-2b788864e4be" version="1.0" xml:lang="en"/>
15:15:43: [Chat] RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
15:15:43: [Chat] SENT: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADM1NTY4My0xMgBuZXdVc2VyQXdlc29tZQ==</auth>
15:15:43: [Chat] status opening 
15:15:43: [Chat] SENT: <open version="1.0" xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="chat.connectycube.com"/>
15:15:43: [Chat] RECV: <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
15:15:43: [Chat] RECV: <open xmlns='urn:ietf:params:xml:ns:xmpp-framing' from='chat.connectycube.com' id='5cd49981-f8dd-40c1-b273-2b788864e4be' version='1.0' xml:lang='en' />
15:15:43: [Chat] status open <open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="chat.connectycube.com" id="5cd49981-f8dd-40c1-b273-2b788864e4be" version="1.0" xml:lang="en"/>
15:15:43: [Chat] RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
15:15:43: [Chat] SENT: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADM1NTY4My0xMgBuZXdVc2VyQXdlc29tZQ==</auth>
15:15:43: [Chat] status opening 
15:15:43: [Chat] SENT: <open version="1.0" xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="chat.connectycube.com"/>

Just want to understand is it a bug or I missed something

DaveLomber commented 5 years ago

Ok, I got it, I should use a promise

  auth(crds).then(function(val) {

  }).catch(function(reason) {

  });
DaveLomber commented 5 years ago

I tried this one:

auth(crds).then(function() {
    }).catch(function(reason) {
        xmppClient.stop();
   });

but still no luck

What's the right way of processing auth failed case?

trampi commented 5 years ago

Hi! You can use the error event handler. See the following code sample:

var XMPP = require('@xmpp/client')
var xmppClient = XMPP.client({
    service: Config.chatProtocol.websocket,
    credentials: function authenticate(auth, mechanism) {
        var crds = {
            username: cbUserName,
            password: cbUserPassword,
        }
        auth(crds)
    }
});

// the folowing code is a handler for errors
xmppClient.on('error', err => {
    console.log('error logging in', err);
    // you can filter on the err object if it is an authentication error.
});

xmppClient.start();

However, it does authenticate again and again. To prevent that, call the following before start()

xmppClient.reconnect.stop();

Be sure to call

xmppClient.reconnect.start();

after a successful authentication to allow the client to reconnect if it looses connection (e.g. after a network error).

DaveLomber commented 5 years ago

@trampi thanks for you reply, but my issue is that I do not receive any 'error' callback

DaveLomber commented 5 years ago

I think there is something wrong with the lib

Here is a log from SUCCESS auth:

19:00:02: [Chat] CONNECTING
19:00:02: [Chat] status opening 
19:00:02: [Chat] SENT: <open version="1.0" xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="chat.connectycube.com"/>
19:00:03: [Chat] RECV: <open xmlns='urn:ietf:params:xml:ns:xmpp-framing' from='chat.connectycube.com' id='a39767e2-3494-41ed-b347-e83cdfb8ce7f' version='1.0' xml:lang='en' />
19:00:03: [Chat] status open <open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="chat.connectycube.com" id="a39767e2-3494-41ed-b347-e83cdfb8ce7f" version="1.0" xml:lang="en"/>
19:00:03: [Chat] RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
19:00:03: [Chat] SENT: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADM1NTY4LTEyAG5ld1VzZXJBd2Vzb21l</auth>
19:00:03: [Chat] status opening 
19:00:03: [Chat] SENT: <open version="1.0" xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="chat.connectycube.com"/>
19:00:03: [Chat] RECV: <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
19:00:03: [Chat] RECV: <open xmlns='urn:ietf:params:xml:ns:xmpp-framing' from='chat.connectycube.com' id='a39767e2-3494-41ed-b347-e83cdfb8ce7f' version='1.0' xml:lang='en' />
19:00:03: [Chat] status open <open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="chat.connectycube.com" id="a39767e2-3494-41ed-b347-e83cdfb8ce7f" version="1.0" xml:lang="en"/>
19:00:03: [Chat] RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><sm xmlns="urn:xmpp:sm:3"/><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features>
19:00:03: [Chat] SENT: <iq type="set" id="uq3okkl3scb" xmlns="jabber:client"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>
19:00:04: [Chat] RECV: <iq to="35568-12@chat.connectycube.com/1204607085-chat-4939" xmlns="jabber:client" id="uq3okkl3scb" type="result"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>35568-12@chat.connectycube.com/1204607085-chat-4939</jid></bind></iq>
19:00:04: [Chat] SENT: <iq type="set" id="77h8sd1rq9g" xmlns="jabber:client"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>
19:00:04: [Chat] status online 35568-12@chat.connectycube.com/1204607085-chat-4939
19:00:04: [Chat] ONLINE
19:00:04: [Chat] CONNECTED

Here is a log from FAILED auth:


19:01:09: [Chat] CONNECTING
19:01:09: [Chat] status opening 
19:01:09: [Chat] SENT: <open version="1.0" xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="chat.connectycube.com"/>
19:01:10: [Chat] RECV: <open xmlns='urn:ietf:params:xml:ns:xmpp-framing' from='chat.connectycube.com' id='e8fc56b3-7ba9-43e9-a9e8-50f932218635' version='1.0' xml:lang='en' />
19:01:10: [Chat] status open <open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="chat.connectycube.com" id="e8fc56b3-7ba9-43e9-a9e8-50f932218635" version="1.0" xml:lang="en"/>
19:01:10: [Chat] RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
19:01:10: [Chat] SENT: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADM1NTY4MC0xMgBuZXdVc2VyQXdlc29tZQ==</auth>
19:01:10: [Chat] status opening 
19:01:10: [Chat] SENT: <open version="1.0" xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="chat.connectycube.com"/>
19:01:10: [Chat] RECV: <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
19:01:10: [Chat] AUTH FAILED [SASLError: not-authorized]
19:01:10: [Chat] RECV: <open xmlns='urn:ietf:params:xml:ns:xmpp-framing' from='chat.connectycube.com' id='e8fc56b3-7ba9-43e9-a9e8-50f932218635' version='1.0' xml:lang='en' />
19:01:10: [Chat] status open <open xmlns="urn:ietf:params:xml:ns:xmpp-framing" from="chat.connectycube.com" id="e8fc56b3-7ba9-43e9-a9e8-50f932218635" version="1.0" xml:lang="en"/>
19:01:10: [Chat] RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
19:01:10: [Chat] SENT: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADM1NTY4MC0xMgBuZXdVc2VyQXdlc29tZQ==</auth>
19:01:10: [Chat] status opening 

And here is a screenshot from other Web client (SUCCESS auth)

connectycube_jasmine_spec_runner_and_recruiting___connectycube

and the same, but for failure case:

failure

Just look at the 2nd 'open' element - the lib sends it despite that fact that I received a 'failure' auth response. I think this is a reason of the issue

trampi commented 5 years ago

Have you added the error handler and disabled reconnect first?

trampi commented 5 years ago

Sorry, responded from my phone and did not see the second picture. The second open after successful auth is correct AFAIR the RFC. In the error case I do not see a second open. Anything else I am missing?

DaveLomber commented 5 years ago

yes, an error handler is added

why I need to disable reconnect? it's not a network issue, so it should not try to reconnect in a case of invalid credentials

Here is a 2nd 'open' element in a case of failure

failed2
DaveLomber commented 5 years ago

I see this second 'open' element comes from 'connection.restart' method https://github.com/xmppjs/xmpp.js/blob/master/packages/connection/index.js#L296

which comes from sasl https://github.com/xmppjs/xmpp.js/blob/master/packages/sasl/index.js#L122

So it seems there is an issue in a sasl component, which does not handle it properly

trampi commented 5 years ago

Could you try to change your code to the following?

    credentials: function authenticate(auth, mechanism) {
        var crds = {
            username: cbUserName,
            password: cbUserPassword,
        }
        return auth(crds); // <--- added return, as auth returns a promise which you discard
    }
DaveLomber commented 5 years ago

Thanks @trampi ! I was thinking about something like this, since it's something related to promises

your solution works great, thx!