Smack 4.2.0-rc2 AccountManager#isSupported() is not working for an unregistered/unauthenticated entity

Following steps describe a possible scenario where an unregistered entity is trying to perform an inBand Registration on a server, manually or implemented in code e.g. aTalk.

  1. The unregistered entity attempts to perform a login and received an message.

  2. Upon received the error message, the system performs a check using AccountManager#isSupported() to determine if the server support inBand registration.

  3. If the IBR is supported, the system proceeds to getRegistrationInfo() to determine the available methods (fields or DataForm) and the parameters required, including an OCR etc feedback if registration is captcha protected.

Note: step 2 may be omitted as per XEP-0077 section 3 Use Cases, step 3 will have the following effect (currently not feedback by AccountManager):

If the host does not support In-Band Registration, it MUST return a

As highlighted in the earlier discussion, the extensionElement in the isSupported() always return null. So it proceeds to use ServiceDiscoveryManager to determined the serverSupportsFeature, but receiving an exception showing in Bold in the log captured below as it requires an autheticated “user” as defined in AbstractXMPPConnection:

/**

  • The full JID of the authenticated user, as returned by the resource binding response of the server.
  • It is important that we don’t infer the user from the login() arguments and the configurations service name, as,
  • for example, when SASL External is used, the username is not given to login but taken from the ‘external’
  • certificate.

*/
protected EntityFullJid user;

However since the entity sign in process has failed, so it does not have the required authenticated “user” to perform the ServiceDiscover operation.

=============================

Smack 4.2.0-beta3 AbstractXMPPConnection#parseFeatures missing case for stream feature

public boolean isSupported()
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
XMPPConnection connection = connection();

ExtensionElement extensionElement = connection.getFeature(Registration.ELEMENT, Registration.NAMESPACE);
if (extensionElement != null) {
return true;
}

return ServiceDiscoveryManager.getInstanceFor(connection).serverSupportsFeature(Registration.NAMESPACE);
}

=================== Log captured during ServerSupportsFeature discovery =======================

01-06 16:59:09.054 ? I/αTalk: [7] impl.protocol.jabber.ProtocolProviderServiceJabberImpl.connectAndLogin().1078 Starting XMPP Connection: jabbim.com/88.86.113.70:5222

01-06 16:59:12.004 ? D/SMACK: SENT (2): <stream:stream xmlns=‘jabber:client’ to=‘jabbim.com’ xmlns:stream=‘http://etherx.jabber.org/streams’ version=‘1.0’ xml:lang=‘en’>

01-06 16:59:12.804 ? D/SMACK: RECV (2): <?xml version='1.0'?><stream:stream xmlns=‘jabber:client’ xmlns:stream=‘http://etherx.jabber.org/streams’ id=‘1075596087585651310’ from=‘jabbim.com’ version=‘1.0’ xml:lang=‘en’>stream:features</stream:features >

01-06 16:59:12.814 ? D/SMACK: SENT (2):

01-06 16:59:13.224 ? D/SMACK: RECV (2):

01-06 16:59:14.454 ? D/SMACK: SENT (2): <stream:stream xmlns=‘jabber:client’ to=‘jabbim.com’ xmlns:stream=‘http://etherx.jabber.org/streams’ version=‘1.0’ xml:lang=‘en’>

01-06 16:59:14.844 ? D/SMACK: RECV (2): <?xml version='1.0'?><stream:stream xmlns=‘jabber:client’ xmlns:stream=‘http://etherx.jabber.org/streams’ id=‘6351479412105391587’ from=‘jabbim.com’ version=‘1.0’ xml:lang=‘en’>

01-06 16:59:14.844 ? D/SMACK: RECV (2): stream:featuresPLAIN</mechanis ms></stream:features>

01-06 16:59:14.844 ? I/αTalk: [7] impl.protocol.jabber.ProtocolProviderServiceJabberImpl.connected().2291 TCP Connection Successful

01-06 16:59:14.894 ? I/αTalk: [7] impl.protocol.jabber.OperationSetBasicTelephonyJabberImpl.registrationStateChan ged().113 Jingle : ON

01-06 16:59:14.894 ? D/SMACK: SENT (2): AGxlb3BhcmQAc29waGlhITUyMA==

01-06 16:59:15.364 ? D/SMACK: RECV (2):

01-06 16:59:15.384 ? E/αTalk: [7] util.account.LoginManager.run().375 Failed to register protocol provider.

java.lang.IllegalArgumentException: Must have a local (user) JID set. Either you didn’t configure one or you where not connected at least once

at org.jivesoftware.smack.filter.IQReplyFilter.(IQReplyFilter.java:91)

at org.jivesoftware.smack.AbstractXMPPConnection.createStanzaCollectorAndSend(Abst ractXMPPConnection.java:747)

at org.jivesoftware.smackx.disco.ServiceDiscoveryManager.discoverInfo(ServiceDisco veryManager.java:539)

at org.jivesoftware.smackx.disco.ServiceDiscoveryManager.discoverInfo(ServiceDisco veryManager.java:505)

at org.jivesoftware.smackx.disco.ServiceDiscoveryManager.supportsFeatures(ServiceD iscoveryManager.java:700)

at org.jivesoftware.smackx.disco.ServiceDiscoveryManager.serverSupportsFeatures(Se rviceDiscoveryManager.java:677)

at org.jivesoftware.smackx.disco.ServiceDiscoveryManager.serverSupportsFeatures(Se rviceDiscoveryManager.java:671)

at org.jivesoftware.smackx.disco.ServiceDiscoveryManager.serverSupportsFeature(Ser viceDiscoveryManager.java:666)

at org.jivesoftware.smackx.iqregisterx.AccountManager.isSupported(AccountManager.j ava:402)

at net.java.sip.communicator.impl.protocol.jabber.LoginByPasswordStrategy.register Account(LoginByPasswordStrategy.java:151)

at net.java.sip.communicator.impl.protocol.jabber.ProtocolProviderServiceJabberImp l.connectAndLogin(ProtocolProviderServiceJabberImpl.java:1137)

at net.java.sip.communicator.impl.protocol.jabber.ProtocolProviderServiceJabberImp l.connectAndLogin(ProtocolProviderServiceJabberImpl.java:876)

at net.java.sip.communicator.impl.protocol.jabber.ProtocolProviderServiceJabberImp l.initializeConnectAndLogin(ProtocolProviderServiceJabberImpl.java:722)

at net.java.sip.communicator.impl.protocol.jabber.ProtocolProviderServiceJabberImp l.register(ProtocolProviderServiceJabberImpl.java:494)

at net.java.sip.communicator.util.account.LoginManager$RegisterProvider.run(LoginM anager.java:369)

I’ve added a check in isSupported, please try the lastest -rc2-SNAPSHOT.

You need to change the isSupported() method to the source as shown below:

After some troubleshooting, I realize that extensionElement is checking against Registration IQ “jabber:iq:register” instead of the stream:features i.e. Registration#Feature “http://jabber.org/features/iq-register”.

After the code modification, then everything is working as expected.

Note: The testing was done with aTalk iqregisterx integration as aTalk is supporting registration using DataForm. I believe the same changes is also applied to iqregister source…

01-07 13:36:56.230 org.atalk.android D/SMACK: RECV (2): stream:features

SCRAM-SHA-1PLAINX-OAUTH2</stream:fea tures>

================ Modified Source ========

public boolean isSupported()
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
XMPPConnection connection = connection();

ExtensionElement extensionElement = connection.getFeature(Registration.Feature.ELEMENT,
Registration.Feature.NAMESPACE);
if (extensionElement != null) {
return true;
}

// Fallback to disco#info only if this connection is authenticated, as otherwise we won’t have an full JID and
// won’t be able to do IQs.
if (connection.isAuthenticated()) {
return ServiceDiscoveryManager.getInstanceFor(connection).serverSupportsFeature(Registration.NAMESPACE);
}
return false;
}

Thanks fixed and uploaded a new snapshot.