powered by Jive Software

Use XMPP server as authentication server

I want to use an XMPP server as an authentication server. The process that will require its services will already have an XMPPConnection to it. Could the existing XMPP connection be used to authenticate other users, or do I have to create a new connection for each authentication?

A connection can be used for various logins, so I’'d say yes.

The login methods say they’‘ll throw an exception if you’‘re already logged in, and I don’'t see any methods that just check credentials.

However, if you create an openfire plugin, you can use the DefaultAuthProvider to check users. Either that, or it’'s time to learn LDAP.

Reusing the connection seems to be problematic. The following code results in the following exception:

XMPPConnection connection = new XMPPConnection(“myserver”);

connection.connect();

connection.login(“kevin3”, “kevin3”);

connection.getSASLAuthentication().authenticate(

“kevin2”,

“kevin2”,

“Authenticator”);

assertTrue(connection.isConnected());

assertTrue(connection.isAuthenticated());

connection.disconnect();

java.net.SocketException: Software caused connection abort: socket write error

at java.net.SocketOutputStream.socketWrite0(Native Method)

at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)

at java.net.SocketOutputStream.write(SocketOutputStream.java:136)

at com.sun.net.ssl.internal.ssl.OutputRecord.writeBuffer(OutputRecord.java:283)

at com.sun.net.ssl.internal.ssl.OutputRecord.write(OutputRecord.java:272)

at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:665)

at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)

at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)

at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)

at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)

at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)

at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)

at java.io.BufferedWriter.flush(BufferedWriter.java:236)

at org.jivesoftware.smack.PacketWriter.writePackets(PacketWriter.java:274)

at org.jivesoftware.smack.PacketWriter.access$000(PacketWriter.java:40)

at org.jivesoftware.smack.PacketWriter$1.run(PacketWriter.java:87)

Also, even if I could manage to authenticate on the same connection, I couldn’'t find a way to close the “Authenticator” resource without disconnecting the entire connection.

The following code works, but it creates a new connection for each authentication (code is Acegi-based, BTW):

protected void additionalAuthenticationChecks(UserDetails userDetails,

UsernamePasswordAuthenticationToken authentication) throws AuthenticationException

{

/*

  • Creates a connection, authenticates the user on it, then closes

  • then connection.

*/

XMPPConnection connection = null;

try

{

connection = new XMPPConnection(xmppAddress);

connection.connect();

try

{

connection.getSASLAuthentication().authenticate(

userDetails.getUsername(),

userDetails.getPassword(),

“Authenticator”);

}
catch (XMPPException e)
{

throw new BadCredentialsException(“SASL authentication failed”, e);

}
}
catch (XMPPException e)
{

throw new AuthenticationServiceException(

“Could not connect to XMPP server for authentication.”, e);

}
finally {

if ( connection != null )

connection.disconnect();

}

}

I suppose I could investigate the Openfire plugin route, but I’'d like to keep things as simple as possible.

Message was edited by: mrpantsuit

Message was edited by: mrpantsuit

Another possibility would be to create your own Packet containing the authentication request and adding a packet listener to watch for the response. Just because the Smack library doesn’‘t provide a direct way to check credentials doesn’‘t mean the server won’'t handle it.

From my brief scan of the core RFC I couldn’'t tell whether this sort of thing was anticipated or not, so you may just have to give it a try. See what the packets Smack sends look like and set yours up the same way.

This is really the sort of thing LDAP was designed for though, and I think it’'s worth learning even though the initial learning curve is fairly steep.

Many thanks for the replies.

Constructing my own packet is an interesting idea, though I’‘m not sure how I’'d wrestle the response packet away from PacketReader; it seems to handle “success”/“failure” stanzas directly.

I’‘m already using XMPP for im/presence services in my system, so it’'s simpler to go ahead use it for user management as well, rather than introducing an LDAP server.

I solved this by creating a new connection and authenticating using a different resource name. The new connection is closed immediately after authentication. A little on the hacky side, but I can live with it for now.