powered by Jive Software

Smack v3.2.1 -- port 5222 works but port 5223 does not

Hi everyone,

As part of a larger project, I have to create and log in to an XMPP Connection so as to subscribe to occasional events published by the server.

I have no choice but to use Smack v3.2.1 – my client insists on that version.

The client also insists that we use port 5223, not 5222, but doesn’t have any knowledge of how Smack works or any restrictions it may have in this respect. I have watched remotely as they ensured that both ports 5222 and 5223 were added to the Windows firewall, and the Windows telnet command line seems to open a connection to both ports, just as a simple test.

With all this in mind, I started out by seeing how far I could get with port 5222 – and it worked fine. ConnectionConfiguration was good, and the connection handle was passed onto XMPPConnection, which was able to log in and join the relevant chat room. Some seconds later I started receiving the relevant published events from the server. All good.

However, it was at this point that the client asked to switch to port 5223, and has installed a security certificate for it. The login attempt now results in this stack trace (the first two lines are output by my own Java):

Temp/Hum XMPPConnection connected ...
Temp/Hum XMPPConnection Login:
org.xmlpull.v1.XmlPullParserException: only whitespace content allowed before start tag and not \u15 (position: START_DOCUMENT seen \u15... @1:1)
at org.xmlpull.mxp1.MXParser.parseProlog(MXParser.java:1519)
at org.xmlpull.mxp1.MXParser.nextImpl(MXParser.java:1395)
at org.xmlpull.mxp1.MXParser.next(MXParser.java:1093)
at org.jivesoftware.smack.PacketReader.parsePackets(PacketReader.java:325)
at org.jivesoftware.smack.PacketReader.access$000(PacketReader.java:43)
at org.jivesoftware.smack.PacketReader$1.run(PacketReader.java:70)

Apologies at this point: I realise there was another post on this forum way back over 10 years ago with a similar problem, but it hasn’t helped me. It seemed to suggest that port 5223 could not be used – is this true ? In the hope that it might make a difference, I specified SecurityMode.enabled but it didn’t help. My code is currently this (it’s the con.login that’s failing when port 5223 is specified, but works for port 5222):

    BXmppConfig xmppConfig = host.getXmppConfig();

    ConnectionConfiguration config = new ConnectionConfiguration(
        host.getAddress(),
        xmppConfig.getPort(),
        xmppConfig.getTempHumidityRoomDomain()
    );
    config.setSecurityMode(SecurityMode.enabled);
    config.setDebuggerEnabled(true);

    XMPPConnection con = new XMPPConnection(config);
    try {
      con.connect();
      System.out.println("Temp/Hum XMPPConnection connected ...");
    } catch (XMPPException e) {
      System.out.println("Temp/Hum XMPPConnection connect failed! Please check server configuration");
      e.printStackTrace();
    }

    try {
      System.out.println("Temp/Hum XMPPConnection Login:");
      con.login(
          xmppConfig.getTempHumidityUser(),
          xmppConfig.getTempHumidityPassword(),
          xmppConfig.getTempHumidityAlias()
      );
      System.out.println("Temp/Hum XMPPConnection login successful");
      startChat(con, xmppConfig);
    } catch (XMPPException e) {
      System.out.println("Temp/Hum XMPPConnection login failed! Please check user credentials");
      e.printStackTrace();
    }

Are there any other hints or tips that anyone can suggest I try, or information I could ask the client to provide me that may add more context to this post ? Can I configure Smack to log some more detailed output to the console regarding what it is doing under the covers ?

Thanks in advance

Although servers and clients can be easily reconfigured otherwise, the default behavior of ports 5222 and 5223 differs in the way that they use TLS / SSL.

On port 5222, connections are initially unencrypted (but allow encryption to be applied through the STARTTLS directive).

On port 5223, encryption is applied to connections immediately (similar to how HTTPS differs from HTTP)

It’s been a long time since I’ve used Smack 3.2.1, but I assume it supports both. I don’t recall the details, but you might need to set a socket factory on the XMPPConfiguration by using .setSocketFactory()

Hi guus,

Thanks for the reply.

I tried what you suggested:

    ConnectionConfiguration config = new ConnectionConfiguration(
        host.getAddress(),
        xmppConfig.getPort(),
        xmppConfig.getTempHumidityRoomDomain()
    );
    config.setSecurityMode(SecurityMode.enabled);
    config.setDebuggerEnabled(true);
    config.setSocketFactory(SSLSocketFactory.getDefault());

    XMPPConnection con = new XMPPConnection(config);
    try {
      con.connect();

Perhaps the javax.net.ssl socket factory is the wrong one to use, I don’t know, but at least I’m getting a more definitive error now:

INFO [07:09:55 13-Jul-21 EDT][crypto] TLS handshake failed. Cause is: failed hostname validation
Temp/Hum XMPPConnection connect failed! Please check server configuration
XMPPError connecting to 172.31.16.11:5223.: remote-server-error(502) XMPPError connecting to 172.31.16.11:5223.
-- caused by: javax.net.ssl.SSLException: failed hostname validation
at org.jivesoftware.smack.XMPPConnection.connectUsingConfiguration(XMPPConnection.java:524)
at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:953)

Any thoughts ?

It actually seems to be working. You are connecting to an XMPP server, that is serving a TLS certificate. What’s going wrong is that none of the subjects that are defined in the certificate match the name of the server that you’re connecting to. Assuming that the certificate is correct, the most likely cause is that you’re using an IP address to establish the connection, instead a domain name.

The first parameter being passed to ConnectionConfiguration is indeed a dotted decimal IP address (i.e. 172.XXX.XXX.XXX). You’re saying, I think, that the IP address won’t match the certificate and so I need to use a FQDN like “hostname.foo.bar.client.com” ?

Gary

Indeed. The certificate will cover at least one domain name, and quite often, it covers multiple (through SAN definitions). When you connect to the server, Smack will, by default, verify that the XMPP domain name and hostname of the server that you’re connecting to is covered by the certificate that the server is providing.

guus,

I certainly seem to be connected, and now logged in too. However, I’m getting SASL Authentication issues. I tried the code both with and without SASL Authentication of “PLAIN”, 0 – but doesn’t seem to make any difference.

Feels close - any more ideas ?

Thank you,

Gary

Start listener for XMPP temperature/humidity events....
Host: NC41W2011.global.blah.myclient.com
Port: 5223
Service Name: conference.global.blah.myclient.com
Socket Factory: SSLSocketFactory
Security Mode: ENABLED
Debugger: ENABLED
SASL configuration: Not in use
Temp/Hum XMPPConnection connected ...
Temp/Hum XMPPConnection Login:
User: Admin
Password: b45683c7-374c-4268-9bc4-xxxxxxxxxxxx
Resource: tempHumidityAlias
Temp/Hum XMPPConnection login successful
Temp/Hum XMPP MultiUserChat join parameter: temperaturehumidityqueue
Temp/Hum XMPP MultiUserChat - join successful
Temp/Hum XMPP MultiUserChat - waiting for events...


java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:990)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:948)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.read1(BufferedReader.java:212)
at java.io.BufferedReader.read(BufferedReader.java:286)
at org.jivesoftware.smack.util.ObservableReader.read(ObservableReader.java:42)
at org.xmlpull.mxp1.MXParser.fillBuf(MXParser.java:2992)
at org.xmlpull.mxp1.MXParser.more(MXParser.java:3046)
at org.xmlpull.mxp1.MXParser.nextImpl(MXParser.java:1144)
at org.xmlpull.mxp1.MXParser.next(MXParser.java:1093)
at org.jivesoftware.smack.PacketReader.parsePackets(PacketReader.java:325)
at org.jivesoftware.smack.PacketReader.access$000(PacketReader.java:43)
at org.jivesoftware.smack.PacketReader$1.run(PacketReader.java:70)

SASL authentication PLAIN failed: not-authorized: 
 at org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:337)
at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:203)
at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:964)
at org.jivesoftware.smack.ReconnectionManager$2.run(ReconnectionManager.java:128)

That seems to be a generic authentication failure (although the reference to a timeout is a bit unexpected).

What caught my eye is that you appear to be connecting to a conference service. That’s typically a subsystem of an XMPP domain. It’s the XMPP domain that you’d authenticate against, not the conference service.

Instead of conference.global.blah.myclient.com try using global.blah.myclient.com

guus,

Tried changing the service name but it didn’t change the error.

There are currently no lines of code referencing anything to do with SASL. Do I need any ?

I’m unsure. That’s both specific to your server configuration, as well as to that ancient version of Smack that you’re using.

One other thing that’s odd is that in your output, this line appears:

Temp/Hum XMPPConnection login successful

That seems to be something written to the output by proprietary code.

After that line is printed, authentication fails - so login could not have been successful, at least not in the traditional way. Is the code trying to log in twice? Is that log line simply incorrect?

Apologies - that’s proprietary logging. Definitely only one login attempt/call.

It’s still weird that things progress (MUC joins that are successful), while authentication is pending.

Apart from that, this seems to be an ordinary authentication issue. That typically means that you’re either using invalid credentials, or are connecting to a different service than what they are valid for.

Without diving deep into the project, I’m not sure if I can be of much more help. If you have access to the server’s log files, maybe you can use those to see if they contain clues.

Hi guus,

I’ve made some progress, albeit limited.

Firstly, we’ve gone back to basics – purely because we’re seeing a problem that may partly explain the port 5223 issue.

So firstly, we’ve returned to port 5222 (needed to take out the SSLSocketFactory).

The conference sub-domain I’ve been quoting actually offers two subscriptions - one for changes of temperature, and one for alarms. There are two separate SOAP calls that have to be made first, one to subscribe to each channel. Each of those two calls then returns a pair of objects: a password and a room name to use for the connection. The two passwords are always different, and the two rooms are always alarmqueue@conference.blah.blah and temperaturequeue@conference.blah.bah.

I then start two threads, one for each subscription, so there’s no danger of cross-contamination of parameters, data, whatever. Even then, the threads are started three seconds apart. Each thread is connecting to the same host, port and service name. The XMPP login for each uses the same username (‘admin’), but they use different passwords (because those are returned by the two previous SOAP calls), and they specify different resource names (e.g. tempAlias and alarmAlias, which I believe can be anything).

Something strange now happens. If I start only the alarm subscription, it works fine (logs in OK). However, if I start both threads (keeping everything else identical), the temperature subscription works fine (logs in OK) but the alarm subscription now throws the SASL exception when it tries to login, even I’ve not changed anything about it.

The two channels will not operate in tandem - only one at a time.

Could this be because the same conference is being logged into twice in quick succession, using the same service and/or the same username ?

Sorry - if this is outside the remit, then I don’t mind being told that and I won’t pester you further – but wondered if anything springs to mind in your experience with Smack ?

We seem to be moving from a generic Smack problem into an issue with working with a proprietary implementation in your organisation.

From what you write, it appears that the solution is making use of multi-user chat rooms to perform some kind of publish/subscribe action. Generically speaking, MUC rooms can optionally be configured to require a password for members to be allowed to enter them. These passwords are conceptually very different from the passwords used to authenticate the XMPP session itself (the initial ‘login’). They can, of course, happen to have the same value.

There is, however, a chance that the solution that you’re working with is modified to behave differently than what’s defined in the XMPP specifications. That’s hard to tell at this point.

I fear that there’s only so much that we can do without properly diving into your custom solution. To move forward, you might want to consider engaging one of the service providers that offer their assistance.

Sure - many thanks for spending time on this. It’s a refreshing change to meet with someone who has genuinely wanted to help and be supportive rather than some of the angry know-it-alls who growl at you on StackOverflow !

Gary

guus,

Some good news is that I think I’m over the problem of operating two rooms together using port 5222 - I needed to generate only one Smack connection, and one login using a single password, and then pass that XMPP connection to two different MultiUserChat instances. We’re about to test but it looks hopeful.

On the 5223 front, I’m still struggling. It really does look like the initial login is still successful, and the two MultiUserChat instances are joining and listening OK. Then, 70 seconds later, there’s an SSLSocket timeout during a read, followed a few seconds later by the Smack Reconnection Manager trying a reconnect (unsuccessfully). This behaviour then just cycles around every 70 seconds (socket timeout on read, followed by failed Smack reconnection) ad infinitum.

I’ll get our customer to look into this, i.e. maybe their server is dropping the configuration when it is connected via 5223.

However, may I just ask one question ? I’ve noticed another post on ignite realtime where someone is told to set their connection configuration’s socket factory to DummySSLSocketFactory, but that’s an Android thing and I’m in a Java environment. Am I OK to use:

config.setSocketFactory(SSLSocketFactory.getDefault());

from the javax.net.ssl package hierarchy ?

Authentication an XMPP connection (regardless whether that’s on port 5222 or 5223) does not have any impact on whatever is afterwards done over the authentication connection. You being able to perform activities while your login times out might mean that you do not need to authenticate at all, to be able to interact with the services?

I believe that you’d ideally should use a ‘proper’ SSLSocketFactory, (like the one that’s returned by your JVM - which might already be the default). That, however, will enforce more strict verification of the certificates than a ‘dummy’ would do (which I believe simply allows all certificates to be used). You might therefor end up being unable to connect. There’s no harm in trying though.

I am curious: Did your client mention any rationale for this?

Flow,

Unfortunately not. I’m not trying to be deliberately mysterious but I don’t have permission to reveal details of the project.

But I can say the following…

The Smack XMPP chat rooms I’m trying to connect to are part of a bigger suite of software developed by a large corporate. They are designed to be subscribed to so that a client can receive ad hoc published changes of values and alarms for building management. I was given an API document to follow which contained some sample Java code to follow in order to subscribe to those two chat rooms. I followed the code to the letter - but I was told an hour ago that the API was written some considerable time ago and was only tested with port 5222 against version 3.2.1 of Smack. Reading between the lines, they struggled to get it working with port 5223 over SSL. They also admitted to me that they need to go back to their R & D department and re-visit the implementation.

As stated in my previous posts, my code (when used with port 5223) pulls in the standard javax.net.ssl SSLSocketFactory.getDefault(), and also sets the configuration’s SecurityMode (I’ve tried both ‘required’ and ‘enabled’ but both failed in different ways), so I’m out of ideas and, since I’m following someone else’s suggested code sample for the use of Smack, I feel I’ve already gone above and beyond my own development remit having tried various ways to solve the issue.

If you feel that a later version of Smack may fix things, I’m happy to pull that uberjar into my project and re-build, as long as someone can guide me as regards SSL socket factory & security mode settings.

Thanks for the reply