SASL custom mechanisms and configuration

Submitted by bmalkow on Wed, 2013-01-23 04:54

This API is available from Tigase XMPP Server version 5.2.0 or our current master branch.

Note that API is under active development. This description may be updated at any time.

Basic SASL configuration

SASL implementation in the Tigase XMPP Server is compatible with Java API.The same exact interfaces are used.

The SASL implementation consists of following parts:

  1. mechanism
  2. CallbackHandler

Properties list for SASL plugin (sess-man/plugins-conf/urn\:ietf\:params\:xml\:ns\:xmpp-sasl):



Property Description
factory A factory class for SASL mechanisms. Detailed description at Mechanisms configuration
callbackhandler A default callback handler class. Detailed description at CallbackHandler configuration
callbackhandler-${MECHANISM} A callback handler class for a particular mechanism. Detailed description at CallbackHandler configuration
mechanism-selector A class for filtering SASL mechanisms available in a stream. Detailed description at Selecting mechanisms

Mechanisms configuration

To add a new mechanism, a new factory for the mechanism has to be registered. It can be done with a new line in the init.properties file like this one:

sess-man/plugins-conf/urn\:ietf\:params\:xml\:ns\:xmpp-sasl/factory=com.example.OwnFactory

The class must implement 'SaslServerFactory' interface. All mechanisms returned by 'getMechanismNames()' method will be registered automatically.

The factory which is available and registered by default is 'tigase.auth.TigaseSaslServerFactory' which provides PLAIN and ANONYMOUS mechanisms.

 

CallbackHandler configuration

The CallbackHandler is a helper class used for loading/retrieving authentication data from data repository and providing them to a mechanism.

To register a new callback handler a new line in the init.properties file like this one has to be added:

sess-man/plugins-conf/urn\:ietf\:params\:xml\:ns\:xmpp-sasl/callbackhandler=com.example.DefaultCallbackHandler

It is also possible to register different callback handlers for different mechanisms:

sess-man/plugins-conf/urn\:ietf\:params\:xml\:ns\:xmpp-sasl/callbackhandler-PLAIN=com.example.PlainCallbackHandler
sess-man/plugins-conf/urn\:ietf\:params\:xml\:ns\:xmpp-sasl/callbackhandler-OAUTH=com.example.OAuthCallbackHandler

During authentication process, the Tigase server always checks for a handler specific to selected mechanisms, and if there is no specific handler a default one is used.

Selecting mechanisms available in the stream

Interface 'tigase.auth.MechanismSelector' is used for selecting mechanisms available in a stream. Method 'filterMechanisms()' should return a collection with mechanisms available based on:

  1. all registered SASL factories
  2. XMPP session data (from 'XMPPResourceConnection' class)

The default selector returns mechanisms from the default Tigase's factory ('TigaseSaslServerFactory') only.

It is possible to use a custom selector by specifying it's class int the init.properties file:

sess-man/plugins-conf/urn\:ietf\:params\:xml\:ns\:xmpp-sasl/mechanism-selector=com.example.OwnSelector

Logging/authentication

After the XMPP stream is opened by a client, the server checks which SASL mechanisms are available for the XMPP session. Depending on whether the stream is encrypted or not, depending on the domain, the server can present different available authentication mechanisms. MechanismSelector is responsible for choosing mechanisms. List of allowed mechanisms is stored in the XMPP session object.

When the client/user begins authentication procedure it uses one particular mechanism. It must use one of the mechanisms provided by the server as available for this session. The server checks whether mechanisms used by the client is on the list of allowed mechanisms. It the check is successful, the server creates 'SaslServer' class instance and proceeds with exchanging authentication information. Authentication data is different depending on the mechanism used.

When the SASL authentication is completed without any error, the Tigase server should have authorized user name or authorized BareJID. In the first case, the server automatically builds user's JID based on the domain used in the stream opening element in 'to' attribute.

If, after a successful authentication, method call: 'getNegotiatedProperty("IS_ANONYMOUS")' returns 'Boolean.TRUE' then the user session is marked as anonymous. For valid and registered users this can be used for cases when we do not want to load any user data such as roster, vcard, privacy lists and so on. This is a performance and resource usage implication and can be useful for use cases such as support chat. The authorization is performed based on the client database but we do not need to load any XMPP specific data for the user's session.

More details about implementation can be found at custom mechanisms development.

 

Built-in mechanisms

PLAIN

TODO!

ANONYMOUS

TODO!

Custom mechanisms development

Mechanism

'getAuthorizationID()' method from 'SaslServer' class should return bare JID authorized user. In case that the method returns only user name such as romeo for example, the server automatically appends domain name to generate a valid BareJID: romeo@example.com. In case the method returns a full, valid BareJID, the server does not change anything.

'handleLogin()' method from 'SessionManagerHandler' will be called with user's Bare JID provided by getAuthorizationID() (or created later using stream domain name).

CallbackHandler

For each session authorization, the server creates a new and separate, empty handler. Factory which creates handler instance allows to inject different objects to the handler, depending on interfaces implemented by the handler class:

  • AuthRepositoryAware - injects AuthRepository;
  • DomainAware - injects domain name within which the user attempts to authenticate
  • NonAuthUserRepositoryAware - injects NonAuthUserRepository, although I have no idea what for...

General remarks

JabberIqAuth used for non-SASL authentication mechanisms uses the same callback as the SASL mechanisms.

Methods '*auth*' in '*Repository' interfaces will be deprecated. These interfaces will be treated as user details providers only. There will be new methods available which will allow for additional login operations on the database such as last successful login recording and so on….

 

Known problems

Because JabberIqAuth is initialized separatelly, we strongly recommend to use more general prefix in init.properties:
sess-man/plugins-conf/${KEY}=${VALUE}
instead of
sess-man/plugins-conf/urn\:ietf\:params\:xml\:ns\:xmpp-sasl/${KEY}=${VALUE}
If JabberIqAuth is disabled, then you don't care about it.

Is it possible to develop a

Is it possible to develop a mechanism in which i authenticate using the connection IP address?

Artur Hefczyc's picture

It is possible, the

It is possible, the connection ID contains a remote IP address and port number of the connected client. You would have to parse the connection ID in your authentication plugin.

That is kind of what i did,

That is kind of what i did, but i had to create a PreProcessor to grab the connection ID and insert it into the session as it was not available on my authentication plugin..

Thanks for the guide.

Thanks for the guide. Something which might not be obvious at first sight is the following:
If you extend your SaslServerFactory from javax.security.sasl.SaslServerFactory you need to override the default mechanism selector as well because the DefaultMechanismSelector only accepts classes which inherit from TigaseSaslServerFactory.

- Michael

Artur Hefczyc's picture

Rui, there is something wrong

Rui, there is something wrong with either your installation or with your code. Connection ID is essential information which is set automatically to the user session object - XMPPResourceConnection. It is available through the public API: getConnectionID().
If it was not working, nothing would work on the server as far as the user connection is concerned.

But how do I get Connection

But how do I get Connection ID in a custom authentication connector (custom class)? Is there a reference for the user session object in any of the property maps passed to the authentication plugin? I've used an Eclipse attached debugger and put a breakpoint in otherAuth of my class to view the properties in the passed argument map, and I can't seem to find any property like it.

Artur Hefczyc's picture

Assuming you are using our

Assuming you are using our XMPPProcessor API as all our plugins do, there is process(...) which is called for all packets handled by the plugin. One of the argument to the method is XMPPResourceConnection object which does have the getConnectioId() method.

The thing is that this is not

The thing is that this is not a session manager plugin like a XMPPProcessor. It's an authentication connector, i.e., it's loaded in tigase using the following line in the init.properties file:

--auth-db = com.myproject.Authenticator

in which this class implements AuthRepository. So I do not have the process(...) method. Do you think this is the wrong approach for a matter of authenticating a user using project specific verifications other than a password?

Artur Hefczyc's picture

Indeed, you have to modify

Indeed, you have to modify the authentication plugin to pass additional data to the authentication connector. You should use authOther(...) method API as it have a Map as a parameter which can contain free form authentication data.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.