Custom Authentication Connectors
Prev | Chapter 6. Security | Next

## Custom Authentication Connectors

This article presents configuration options available to the administrator and describe how to set Tigase server up to use user accounts data from a different database.

The first thing to know is that Tigase server always opens 2 separate connections to the database. One connection is used for user login data and the other is for all other user data like the user roster, vCard, private data storage, privacy lists and so on…​

In this article we still assume that Tigase server keeps user data in it’s own database and only login data is retrieved from the external database.

At the moment Tigase offers following authentication connectors:

- 'mysql', 'pgsql', 'derby' - standard authentication connector used to load user login data from the main user database used by the Tigase server. In fact the same physical implementation is used for all JDBC databases.
- 'drupal' - is the authentication connector used to integrate the Tigase server with Drupal CMS.
- 'libresource' - is the authentication connector used to integrate the Tigase server with Libresource Collaboration platform.
- 'tigase-auth' - is the authentication connector which can be used with any database. It executes stored procedures to perform all actions. Therefore it is a very convenient way to integrate the server with an external database if you don’t want to expose the database structure. You just have to provide a set of stored procedures in the database. While implementing all stored procedures expected by the server might be a bit of work it allows you to hide the database structure and change the SP implementation at any time. You can add more actions on user login/logout without restarting or touching the server. And the configuration on the server side is very simple. For detailed description of this implementation please refer to Tigase Auth documentation.
- 'tigase-custom' - is the authentication connector which can be used with any database. Unlike the 'tigase-auth' connector it allows you to define SQL queries in the configuration file. The advantage of this implementation is that you don’t have to touch your database. You can use either simple plain SQL queries or stored procedures. The configuration is more difficult as you have to enter carefully all SQL queries in the config file and changing the query usually involves restarting the server. For more details about this implementation and all configuration parameters please refer to Tigase Custom Auth documentation.

As always the simplest way to configure the server is through the init.properties file. In the article describing this file you can find long list with all available options and all details how to handle it. For the authentication connector setup however we only need 2 options:

- '--auth-db = connector'
- '--auth-db-uri = database connection url'

If you happen to keep the user data in the same database as user authentication data you can even skip the second parameter as Tigase automatically assumes settings from the '--user-db-uri' it '--auth-db-uri' is missing.

'--auth-db-uri' stored a standard JDBC connection URL and is exactly the same as for all other settings. For example if you store authentication data in a 'drupal' database on 'localhost' the URL might look like:

    --auth-db-uri = jdbc:mysql://localhost/drupal?user=user&password=passwd

'--auth-db' stored just a connector name or connector implementation class. For convenience Tigase has predefined short names for the most common connectors but you can always use the class name if you know it. You have to use a class name if you want to attach your own authentication connector. The following 2 settings are equal:

    --auth-db = tigase-auth

    --auth-db = tigase.db.jdbc.TigaseAuth

In the same exact way you can setup connector for any different database type:

    --auth-db = drupal

    --auth-db = tigase-custom

You can normally skip configuring connectors for the default Tigase database format: 'mysql', 'pgsql' and 'derby' as they are applied automatically if the parameter is missing.

One more important thing to know is that you will have to modify '--user-db-uri' if you use a custom authentication connector. This is because if you retrieve user login data from the external database this external database is usually managed by an external system. User accounts are added without notifying Tigase server. Then, when the user logs in and tries to retrieve the user roster, the server can not find such a user in the roster database.

To keep user accounts in sync between the authentication database and the main user database you have to add following option to the end of the database connection URL: 'autoCreateUser=true'.

For example:

    --user-db-uri=jdbc:mysql://localhost/tigasedb?user=nobody&password=pass&autoCreateUser=true

If you are interested in even further customizing your authentication connector by writing your own queries or stored procedures, please have a look at 2 following guides:

- Tigase Auth guide
- Tigase Custom Auth guide

### Tigase Auth Connector

The Tigase Auth connector with shortcut name: tigase-auth is implemented in the class: tigase.db.jdbc.TigaseAuth. It allows you to connect to any external database to perform user authentication. You can find more details how to setup a custom connector in the Custom Authentication Connectors guide.

To make this connector working you have to prepare your database to offer set of stored procedures for Tigase server to perform all the authentication actions. The best description is the example schema with all the stored procedures defined. Please refer to the Tigase SVN repository for the schema definition files.

Files with the stored procedures implementations are located in postgresql-schema-4.sql file for PostgreSQL database.

The absolute minimum of stored procedures you have to implement is:

- TigUserLoginPlainPw - to perform user authentication. The procedure is always called when the user tries to login to the XMPP server. This is the only procedure which must be implemented and actually must work.
- TigUserLogout - to perform user logout. The procedure is always called when the user logouts or disconnects from the server. This procedure must be implemented but it can be empty and can do nothing. It just needs to exist because Tigase expect it to exist and attempts to call it.

With these 2 above stored procedures you can only perform user login/logouts on the external database. You can’t register a user account, change user password or remove the user. In many cases this is fine as all the user management is handled by the external system.

If you however want to allow for account management via XMPP you have to implement also following procedures:

- TigAddUserPlainPw - to add a new user account
- TigRemoveUser - to remove existing user account
- TigUpdatePasswordPlainPw - to change a user password for existing account

### Tigase Custom Auth Connector

The Tigase Custom Auth connector with shortcut name: tigase-custom is implemented in the class: tigase.db.jdbc.TigaseCustomAuth. It allows you to connect to any external database to perform user authentication and use a custom queries for all actions.

You can find more details how to setup a custom connector in the Custom Authentication Connectors guide.

The basic configuration is very simple:

    --auth-db = tigase-custom
    --auth-db-uri = jdbc:mysql://localhost/drupal?user=user&password=passwd

That’s it.

The connector loads correctly and starts working using predefined, default list of queries. In most cases you also might want to define your own queries in the configuration file. The shortest possible description is the following example of the content from the init.properties file:

    # This query is used to check connection to the database, whether it is still alive or not
    basic-conf/auth-repo-params/conn-valid-query=select 1

    # This is database initialization query, normally we do not use it, especially in
    # clustered environment
    basic-conf/auth-repo-params/init-db-query=update tig_users set online_status = 0

    # Below query performs user authentication on the database level.
    # The Tigase server does not need to know authentication algorithm or password
    # encoding type, it simply passes user id (BareJID) and password in form
    # which was received from the client, to the stored procedure. If the
    # authentication was successful the procedure returns user bare JID or null otherwise.
    # The Tigase checks whether the JID returned from the query matches
    # JID passed as a parameter. If they match, the authentication is successful.
    basic-conf/auth-repo-params/user-login-query={ call TigUserLoginPlainPw(?, ?) }

    # Below query returns number of user accounts in the database, this is mainly used
    # for the server metrics and monitoring components.
    basic-conf/auth-repo-params/users-count-query={ call TigAllUsersCount() }

    # Below query is used to add a new user account to the database
    basic-conf/auth-repo-params/add-user-query={ call TigAddUserPlainPw(?, ?) }

    # Below query is used to remove existing account with all user's data from the database
    basic-conf/auth-repo-params/del-user-query={ call TigRemoveUser(?) }

    # This query is used for the user authentication if "user-login-query" is not defined,
    # that is if there is no database level user authentication algorithm available. In such
    # a case the Tigase server loads user's password from the database and compares it
    # with data received from the client.
    basic-conf/auth-repo-params/get-password-query=select user_pw from tig_users where user_id = ?

    # Below query is used for user password update in case user decides to change his password
    basic-conf/auth-repo-params/update-password-query=update tig_users set user_pw = ? where user_id = ?

    # Below query is called on user logout event. Usually we use a stored procedure which
    # records user logout time and marks user as offline in the database
    basic-conf/auth-repo-params/user-logout-query=update tig_users, set online_status = online_status - 1 where user_id = ?

    # This is configuration setting to specify what non-sasl authentication mechanisms
    # expose to the client
    basic-conf/auth-repo-params/non-sasl-mechs=password,digest

    # This is configuration setting to specify what sasl authentication mechanisms expose to the client
    basic-conf/auth-repo-params/sasl-mechs=PLAIN,DIGEST-MD5

Queries are defined in the configuration file and they can be either plain SQL queries or stored procedures. If the query starts with characters: '\{ call' then the server assumes this is a stored procedure call, otherwise it is executed as a plain SQL query. Each configuration value is stripped from white characters on both ends before processing.

Please don’t use semicolon ';' at the end of the query as many JDBC drivers get confused and the query may not work.

Some queries can take arguments. Arguments are marked by question marks '?' in the query. Refer to the configuration parameters description for more details about what parameters are expected in each query.

The first example shows how to put a stored procedure as a query with 2 required parameters.

    add-user-query={ call TigAddUserPlainPw(?, ?) }

The same query with plain SQL parameters instead:

    add-user-query=insert into users (user_id, password) values (?, ?)

The order of the query arguments is important and must be exactly as described in specification for each parameter.

- 'conn-valid-query' - Query executing periodically to ensure active connection with the database.

  Takes no arguments.

  Example query: 'select 1'

- 'init-db-query' - Database initialization query which is run after the server is started.

  Takes no arguments.

  Example query: 'update tig_users set online_status = 0'

- 'add-user-query' - Query adding a new user to the database.

  Takes 2 arguments: (user_id (JID), password)

  Example query: 'insert into tig_users (user_id, user_pw) values (?, ?)'

- 'del-user-query' - Removes a user from the database.

  Takes 1 argument: (user_id (JID))

  Example query: 'delete from tig_users where user_id = ?'

- 'get-password-query' - Retrieves user password from the database for given user_id (JID).

  Takes 1 argument: (user_id (JID))

  Example query: 'select user_pw from tig_users where user_id = ?'

- 'update-password-query' - Updates (changes) password for a given user_id (JID).

  Takes 2 arguments: (password, user_id (JID))

  Example query: 'update tig_users set user_pw = ? where user_id = ?'

- 'user-login-query' - Performs user login. Normally used when there is a special SP used for this purpose. This is an alternative way to a method requiring retrieving user password. Therefore at least one of those queries must be defined: user-login-query or get-password-query.

  If both queries are defined then user-login-query is used. Normally this method should be only used with plain text password authentication or sasl-plain.

  Tigase expects a result set with user_id to be returned from the query if login is successful and empty results set if the login is unsuccessful.

  Takes 2 arguments: (user_id (JID), password)

  Example query: 'select user_id from tig_users where (user_id = ?) AND (user_pw = ?)'

- 'user-logout-query' - This query is called when user logs out or disconnects. It can record that event in the database.

  Takes 1 argument: (user_id (JID))

  Example query: 'update tig_users, set online_status = online_status - 1 where user_id = ?'

- 'non-sasl-mechs' - Comma separated list of NON-SASL authentication mechanisms. Possible mechanisms are: password and digest. The digest mechanism can work only with get-password-query active and only when password are stored in plain text format in the database.

- 'sasl-mechs' - Comma separated list of SASL authentication mechanisms. Possible mechanisms are all mechanisms supported by Java implementation. The most common are: PLAIN, DIGEST-MD5, CRAM-MD5.

  "Non-PLAIN" mechanisms will work only with the get-password-query active and only when passwords are stored in plain text format in the database. Application: Tigase Server

### Drupal Authentication

Currently, we can only check authentication against a Drupal database at the moment. Full Drupal authentication is not implemented as of yet.

As Drupal keeps encrypted passwords in database the only possible authorization protocols are those based on PLAIN passwords.

To protect your passwords Tigase server must be used with SSL or TLS encryption.

Implementation of a Drupal database based authorization is located in tigase.db.jdbc.DrupalAuth class. Although this class is capable of adding new users to the repository I recommend to switch in-band registration off due to the caching problems in Drupal. Changes in database are not synchronized with Drupal yet. Functionality for adding new users is implemented only to ease user accounts migration from different repository types from earlier Tigase server installations.

The purpose of that implementation was to allow all accounts administration tasks from Drupal like: account creation, all accounts settings, like e-mail, full name, password changes and so on.

Tigase server uses following fields from Drupal database: name (user account name), pass (user account password), status (status of the account). Server picks up all changes instantly. If user status is not 1 then server won’t allow user to login trough XMPP even if user provides valid password.

There is no Roster management in Drupal yet. So Roster management have to be done from the XMPP client.

### LDAP Authentication Connector

From version 5.1.0, rev. (build) 2881 Tigase XMPP Server offers support for authenticating users against an LDAP server in Bind Authentication mode.

Configuration for the LDAP support is really simple you just have to add a few lines to your init.properties file.

    # LDAP Authentication connector
    --auth-db = tigase.db.ldap.LdapAuthProvider
    # LDAP connection URI
    --auth-db-uri=ldap://ldap.tigase.com:389
    # LDAP access parameters
    basic-conf/auth-repo-params/user-dn-pattern=cn=USER_ID,ou=people,dc=tigase,dc=org

Please note the USER_ID element, this is a special element of the configuration which is used to authenticate particular user. Tigase LDAP connector replaces it with appropriate data during authentication. You can control what Tigase should put into this part. In your configuration you must replace this string with one of the following:

1. %1$s - use user name only for authentication (JabberID’s localpart)
2. %2$s - use domain name only for authentication (JabberID’s domain part)
3. %3$s - use the whole Jabber ID (JID) for authentication

### Configuration of SASL EXTERNAL

In order to enable SASL External add following line to the init.properties file

    c2s/clientCertCA=/path/to/cacert.pem

File cacert.pem contains Certificate Authority certificate which is used to sign clients certificate.

Client certificate must include user’s Jabber ID as XmppAddr in subjectAltName:

> As specified in RFC 3920 and updated in RFC 6120, during the stream negotiation process an XMPP client can present a certificate (a “client certificate”). If a JabberID is included in a client certificate, it is encapsulated as an id-on-xmppAddr Object Identifier (“xmppAddr”), i.e., a subjectAltName entry of type otherName with an ASN.1 Object Identifier of “id-on-xmppAddr” as specified in Section 13.7.1.4 of RFC 6120.[1]

It is possible to make client certificate required:

    c2s/clientCertRequired[B]=true

If this option will be enabled, then client must provide certificate. This certificate will be verified against c2s/clientCertCA. If client does not provide certificate or certificate will be invalid, TLS handshake will be interrupted and client will be disconnected.

Using this options does not force client to use SASL EXTERNAL. Client still may authenticate with other SASL mechanisms.

[1] XEP-0178

Prev | Up | Next
Server Certificates | Home | Packet Filtering