Admin guide

This is a guide for system administrators who want to install and maintain Tigase Jabber/XMPP server.

About Tigase Jabber/XMPP Server

Tigase Jabber/XMPP Server is Open Source and Free (GPLv3) Java based server. The goals behind the design and implementation of the server are:

  1. Make the server robust and reliable.
  2. Make the server secure communication platform.
  3. Make flexible server which can be applied to different use cases.
  4. Make extensible server which takes full advantage of XMPP protocol extensibility.
  5. Make the server easy to setup and maintain.
Robust and reliable.

By robust and reliable server I mean the server which can handle many concurrent requests/connections and can run for a log time. By many concurrent requests/connections I mean as many as it is needed. The server is designed and implemented to handle milions of simultaneous connections.

It is not enough however to design and implement high load server and hope it will run well. The main focus in the project is put in tests. Tests are taken so seriously that dedicated testing framework has been implemented. All server functions are considered as implemented only when they pass testing cycle. The testing cycle consists of 3 fundamental tests:

  1. Functional tests - checking whether the function works at all.
  2. Performance tests - checking whether the function performs well enough.
  3. Stability tests - checking whether the function behaves well in long term run. It must handle hundreds of requests a second in several hours server run.
Security

There are a few elements of the security related to Jabber/XMPP server: secure data transmissions which is met by the implementation of SSL or TLS protocol, secure user authorization which is met by the implementation of DIGEST or SASL user authorization and secure deployment which is met by component architecture.

Secure deployment is a software installation which doesn't impact network security. Companies usually have their networks divided into 2 parts: DMZ which is partially open to outside world and Private network which is closed to outside world.

If the Jabber/XMPP server have to provide effective way of communication between company employees regardless they are in company office or outside (perhaps at customer site) it needs to accept connections from outside world. So the natural place for server deployment is a DMZ part. There is an issue however with such installation. Each company has normally established network users base and integrated authorization mechanisms. So it would be very good if Jabber server could use this mechanisms for users authorizations as well. Usually, however, authorization information is not available in DMZ and it shouldn't be.

Tigase server offers solution for such case. With it's component structure it can be easily deployed on any number machines and from the user point of view it is seen as a one logical Jabber server. So in our case we can install Session Manager module in private network part and Client Connection Manager with Server Connection Manager in DMZ.

Session Manager connects to DMZ and receives all packets from users. Thus is can securely realize users authorization based on company authorization mechanisms.

Flexibility
There are many different Jabber/XMPP server use cases. The most obvious are:

  • Used as bussiness communication platform in small and medium companies server is not under heavy load. Instead for such deployments security is a key feature.
  • Fo huge community websites or internet portals server is on the other side usually under very heavy load and have to support tousands or millions of simultaneous connections and for such deployment we talk about different kind of security as the service is open to public anyway.
  • For very small community deployments or for small home networks the key factor is ease to deploy and maintain.

Architecture based on components allows you to run selected modules on separate machines so the server can be easily applied to all scenarios.

For simple installation server generates config file which can be used almost stright away with very few modifications or sometimes even no config editing is required. For complex deployments though you can tweak configuration to your needs and setup Jabber server on as many physical machines as you need.

Extensibility

The world changes all the time so people needs change as well. Jabber/XMPP protocol has been designed to be extensible to make it easy adding new features and apply it to different needs. As a result Jabber is a very effective platform not only for sending messages to mates. It can also be extended for sending instant notifications about events, it can be useful platform for on-line customer service, voice communication and all other cases where sending information instantly to other people is needed.

Tigase server has been designed to be extensible as well. Of course modular architecture makes it extensible as you can easily replace component which doesn't fullfill your requirements with another one better fitting your needs. But this is not all. Another factor of extensibility is how easy is to replace component or add new extensions. The great focus has been put in server design API to make it easy for other software developers to create extensions and implement new features.

Easy

Complex computer networks consisting of many servers with different services are hard to maintain. There is no other way than employing professional staff and looking after the network.

Not all networks are so complex however. Most small companies have just a few servers for their needs with services like e-mail, HTTP server with company website and that's it. They might want to add Jabber server to the collection of their services and don't want to dedicate much resources on setting it up and later maintenance. For such users default configuration is pretty much what they need. If operating system on the server is well configured then Tigase should pickup correct hostname.

Tigase server is designed and implemented to allow dynamic reconfiguration at runtime so there is no need for restarting server each time you want to change a configuration settings.

There are also interfaces and handlers available to make it easy to implement web user interface for server monitoring and configuring. Such user interface will included in one of future releases.

Generic documents - applying to all the Tigase server versions

This section keeps set of documents which apply to all the Tigase server version and contain more generic or introductory information.

Configuration

Configuration settings are kept in XML file very similar in it's structure to Java 5.0 preferences file. The most significant difference is possibility to assign multiple values to one key (entry). Another difference is that in configuration file all values are uu-encoded so it is possible to keep different data in configuration even if they could cause xml parsing errors.

If you need sample configuration file containing all used defaults just run server in usual way. If configuration file can not be found it is created with default settings. And even if there is an old configuration file with some settings missing server automatically adds missing entries at startup time.

Configuration details

If you look inside configuration file you can see that this is just normal XML file with a few top-level separate sections. These sections are called components.

This is it. Tigase server consists of components and without components there is no application at all. This is why the only configuration settings you can find there are only under some component level.

More precisely top level element in this XML file is called: <tigase-config/> and it doesn't contain any top level configuration settings.

Under the top level element there are at least 2 or more <component/> elements. Each component can be distinguished from others by it's 'name'. That is, 'name' attribute is mandatory and must be distinct within configuration file. It is just component ID. Each component can be named any way you like it doesn't need to mean anything. It is just easier to manage configuration if you select sensible names.

<component/> elements keep configuration settings for server modules.

Example 1:

<tigase-config>
  <component name="basic-conf">
    .... settings
  </component>
  <component name="message-router">
    .... settings
  </component>
</tigase-config>

Configuration settings are kept in "simple" maps like structures (key, values, type) triplets.

  • key is a configuration parameter identifier or a name of the parameter
  • values are just values of the parameter identified by the key. Usually this is just a single value but in some cases there can me more than just one value.
  • type all configuration parameters have a type. In most cases this is just a String. Other possible types are: Boolean, Integer, Long and corresponding array types: String[], Boolean[], int[], long[].

Configuration settings are stored in <map/> element which contains list of <entry/> elements. If there are multiple values for a parameter they are stored as a list of <item> elements.

Example 2:

<map>
   <entry value="localhost" type="String" key="remote-host"/>
   <entry value="false" type="Boolean" key="demo-mode"/>
   <entry value="1000" type="Integer" key="max-queue-size"/>
   <entry type="String[]" key="hostnames">
      <item value="test-a"/>
      <item value="localhost"/>
   </entry>
   <entry type="int[]" key="ports">
      <item value="5222"/>
      <item value="5223"/>
   </entry>
</map>

Configuration settings can be organised hierarchically using <node> elements:

Example 3:

<component name="c2s">
  <map>
    <entry type="String[]" key="hostnames">
      <item value="test-d"/>
      <item value="localhost"/>
    </entry>
  </map>
  <node name="connections">
    <map>
      <entry type="int[]" key="ports">
         <item value="5222"/>
         <item value="5223"/>
      </entry>
    </map>
    <node name="5222">
      <map>
         <entry value="localhost" type="String" key="remote-host"/>
         <entry value="plain" type="String" key="socket"/>
         <entry value="accept" type="String" key="type"/>
      </map>
    </node>
  </node>
</component>

Detailed description for all possible settings is split to per-component chapter. Please look for particular component description for details.

Old way - editing configuration file manually

Options you most likely have to change at deployment time are:

  1. Admin accounts - account names where all admin messages are sent.
  2. Hostnames - real and virtual hostnames your server has to serve for.
  3. Logs - setting related to log file location and how much information should be logged there.

Please let me know if you think more options should be described here.

At the moment the only way to change configuration is to manually edit XML config file. So be prepared for tough times. The good news it that more user friendly interfaces are scheduled for next release. And it will be also reconfigure server at runtime without need to restart service.

Admin accounts

This is the most likely thing to change after you install server and generate default configuration. Actually it is also the easiest option to customize.

Open tigase-config.xml in you favorite text editor and search for string: "admins". You should find section looking like this:

   <entry type="String[]" key="admins">
    <item value="admin%40your.hostname.com"/>
    <item value="admin%40localhost"/>
   </entry>

Characters "%40" stand for '@'. So assuming you have just 1 admin account on your installation which is: "frank@jabber.example.com" you need to replace above code with:

   <entry type="String[]" key="admins">
    <item value="frank%40jabber.example.com"/>
   </entry>

And yes, you can just remove second entry with admin account: "admin@localhost" unless you really want to keep it. Be aware though all system messages will be sent to ALL admin accounts.

Well, if the account does not exists the message is discarded and a warning is be printed in log file. Again, read it again, the previous sentence...

It means that the admin account has to be also created in normal way on the Jabber server. Just register it using your Jabber client. The admin accounts setting works just as a forward instruction. So as a result all system and admin messages are forwarded to all admin accounts if they exist.

Obviously you can have admin accounts as many as you like:

   <entry type="String[]" key="admins">
    <item value="frank%40jabber.example.com"/>
    <item value="lucy%40jabber.example.com"/>
    <item value="mark%40jabber.example.com"/>
    <item value="brenda%40jabber.example.com"/>
    <item value="luck%40jabber.example.com"/>
   </entry>
Hostnames

This one might be a little bit more tricky than previous as hostnames setting has to be changed in a few places. Don't ask why now as this is "Short configuration guide", you remember. Here we focus on how not on why.

You have to search configuration file for string "hostnames". There are more than one such sections and you have to find ALL sections looking like:

   <entry type="String[]" key="hostnames">
    <item value="your.hostname.com"/>
    <item value="localhost"/>
   </entry>

It may also look like:

   <entry type="String[]" key="hostnames">
    <item value="localhost"/>
   </entry>

Depending how successful was mechanism for automatic hostname detection. It of course does not depends on your luck. It depends on network configuration on your server.

The first form is more useful as it includes also hostname recognized in network environment. If it is correct then you can just leave it as it is. If it is incorrect you have to change it. Please remember, if you want your server to be able to communicate with other Jabber/XMPP servers the hostname you put there must resolve in DNS to your Jabber server machine IP address. In other words. If you try to connect from the Internet to machine with this hostname the connection should reach your Jabber server.

And remember your Jabber server users' JIDs (Jabber IDs) can include only those hostnames which are included in the configuration. So for our case you can use only JIDs: "user2@your.hostname.com", "user1@your.hostname.com" and so on.

If you server have more Internet addresses (virtual domains) assigned to it your Jabber server can use them all. So your configuration may look like:

   <entry type="String[]" key="hostnames">
    <item value="your.hostname.com"/>
    <item value="clien1.hostname.com"/>
    <item value="another.hostname.com"/>
    <item value="jabber.sample-domain.com"/>
    <item value="jabber.some-project.org"/>
    <item value="localhost"/>
   </entry>

In such case users' JIDs on your Jabber server may include any of defined above domains like: "user1@your.hostname.com", "user1@clien1.hostname.com", "user1@jabber.sample-domain.com". Each of these 3 sample JIDs refer to different user account.

Your server will accept connections only for domains defined in configuration file.

In majority cases it does not matter whether you leave "localhost" or remove it. It is sometimes better to leave it though. So if you are not sure if you can remove it in your environment just leave it as is.

Logs

Logging mechanism is very flexible in Tigase server. You can adjust separate logging level for each single component. You can also direct loggin to many different destinations like console, file, network socket and so on. Unfortunately it also mean it is a bit complex. The general idea however is quite simple so once you understand it it shouldn't be difficult for you anymore. This guide however describes logging very briefly. Loot at full configuration documentation for detailed explanation.

In standard sever configuration you usually want to turn off all logging to console and all warning and more serious notices directed to log file. Let's say logs will be written to /var/log/tigase-server.log which shouldn't get bigger than 10MB and 5 old logs will be preserved. Here are instructions how to set options.

Open tigase-config.xml in you favorite text editor and search for string: "logging". You should find section looking like this:

  <node name="logging">
   <map>
    <entry value="FINE" type="String" key=".level"/>
    <entry value="java.util.logging.ConsoleHandler+java.util.logging.FileHandler" type="String" key="handlers"/>
    <entry value="tigase.util.LogFormatter" type="String" key="java.util.logging.ConsoleHandler.formatter"/>
    <entry value="WARNING" type="String" key="java.util.logging.ConsoleHandler.level"/>
    <entry value="true" type="String" key="java.util.logging.FileHandler.append"/>
    <entry value="5" type="String" key="java.util.logging.FileHandler.count"/>
    <entry value="tigase.util.LogFormatter" type="String" key="java.util.logging.FileHandler.formatter"/>
    <entry value="ALL" type="String" key="java.util.logging.FileHandler.level"/>
    <entry value="100000" type="String" key="java.util.logging.FileHandler.limit"/>
    <entry value="logs%2Ftigase.log" type="String" key="java.util.logging.FileHandler.pattern"/>
    <entry value="true" type="String" key="tigase.useParentHandlers"/>
   </map>
  </node>

Assuming we make this guide easy and strightforward let me show how this section should look like after modification. So you could just copy and paste it to your config file without going into details. After the configuration code I will briefly explain what each line means so you should be able to further adjust settings for your needs.

  <node name="logging">
   <map>
    <entry value="WARNING" type="String" key=".level"/>
    <entry value="java.util.logging.ConsoleHandler+java.util.logging.FileHandler" type="String" key="handlers"/>
    <entry value="tigase.util.LogFormatter" type="String" key="java.util.logging.ConsoleHandler.formatter"/>
    <entry value="tigase.util.LogFormatter" type="String" key="java.util.logging.FileHandler.formatter"/>
    <entry value="OFF" type="String" key="java.util.logging.ConsoleHandler.level"/>
    <entry value="true" type="String" key="java.util.logging.FileHandler.append"/>
    <entry value="5" type="String" key="java.util.logging.FileHandler.count"/>
    <entry value="ALL" type="String" key="java.util.logging.FileHandler.level"/>
    <entry value="10000000" type="String" key="java.util.logging.FileHandler.limit"/>
    <entry value="%2Fvar%2Flog%2Ftigase-server.log" type="String" key="java.util.logging.FileHandler.pattern"/>
    <entry value="true" type="String" key="tigase.useParentHandlers"/>
   </map>
  </node>

Each line explained:

<entry value="WARNING" type="String" key=".level"/>

Effectively we set WARNING level for all possible logs for all possible components. So more detailed logging information will be discarded. All possible log levels are: OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL.

<entry value="java.util.logging.ConsoleHandler+java.util.logging.FileHandler" type="String" key="handlers"/>

We set 2 handlers for logging information: console and file handler. As we are going to turn off logging to console we could remove all configuration settings for console handler as well. It would simplify configuration file. I don't recommend it though. If there are any problems with your installation switching console logging on might be very helpful and if you remove these settings from config file it may be difficult to bring them back. Hm... maybe not with such excellent documentation.... ;-)

<entry value="tigase.util.LogFormatter" type="String" key="java.util.logging.ConsoleHandler.formatter"/>
<entry value="tigase.util.LogFormatter" type="String" key="java.util.logging.FileHandler.formatter"/>

We set here log formatter for console and file handler. Standard Java handlers print each log message in 2 lines. Tigase formatter prints all logging info in 1 line which make it much easier to filter logs by log type, logging component or log level or whatever you wish. You can just use simple sed command and that's it.

<entry value="OFF" type="String" key="java.util.logging.ConsoleHandler.level"/>

Here we just switch console handler off. To switch it on back set any different level from the list above.

<entry value="true" type="String" key="java.util.logging.FileHandler.append"/>

This settings is to controll whether we want to append logs into old log file or we want to create new log file (removing old content) each time server is restarted.

<entry value="5" type="String" key="java.util.logging.FileHandler.count"/>

Sets number of old log files to preserve to 5.

<entry value="ALL" type="String" key="java.util.logging.FileHandler.level"/>

This line sets the logging level for file handler. Here we set that we want all possible logs to be written to the file. The global level setting however says that only WARNING logs will be generated. So if you want to have more detailed logs you need to adjust global logging level.

<entry value="10000000" type="String" key="java.util.logging.FileHandler.limit"/>

Log file maximum size set to 10MB. After reaching this size the log file is closed and new file is created.

<entry value="%2Fvar%2Flog%2Ftigase-server.log" type="String" key="java.util.logging.FileHandler.pattern"/>

Location of the log file and file name: /var/log/tigase-server.log. Please note %2F instead of '/' character.

<entry value="true" type="String" key="tigase.useParentHandlers"/>

This setting requires going into more details so it is explained in comprehensive configuration guide.

Debuging Tigase

If something goes wrong and you can't find out why it is not working as you expect you might want more detailed debugging options switched on.

Tigase is a Java application and it uses Java logging library this gives you flexibility to switch logging on for selected java package or even for a single Java class.

Logs files are stored in logs/ directory. tigase-console.log keeps all the data but only basic logs. tigase.log.N files keep all the detailed logging entries. So this is the place where you should look in case of problems.

The easy way - init.properties file

The easiest way to change logging for the Tigase package is modifying in init.properies following line:

--debug=server

The line above says: "Switch on ALL debug messages for packet: tigase.server". The tigase.server packet keeps all component's classes. So it allows you to monitor what is going on in each component. What packets it receives and what it is sending out.

Usually people want to see what is going on the network level. That is what has been sent and what has been received by the server - the actual character data. The class which would print all received and sent character data is: tigase.xmpp.XMPPIOService. To enable all debugging info for this class you have to modify the debug line:

--debug=xmpp.XMPPIOService

Note, you skip the tigase. part.

You can also have debugging switched on for many packages/classes at the same time:

--debug=server,xmpp.XMPPIOService

Other packages you might be interested in are:

  • tiagse.io and tigase.net which can print out what is going on a very low level network level including TLS/SSL stuff.
  • tigase.xml would print the XML parser debugging data.
  • tigase.cluster would print all the clustering related stuff. So if you have clustered installation you might be interested in debug settings:
    --debug=server,cluster
    
  • tigase.xmpp.impl would print logs from all plugins loaded to the Tigase server.

and so on...

This method, however has 2 main disadvantages:

  1. You have to remove your XML config file and regenerate it which might be inconvenient.
  2. You can't set logging this way for classes and packages other than tigase. package. And this might be a problem if you include your own code in and load it into the server.

The more difficult but more powerful - tigase.xml file

If you want to modify debugging settings without regenerating the whole XML config file you can modify it yourself manually and add debug entries. This must be done very carefully or you break the XML file and configuration won't work.

Anyway. Open the XML config file with some good text editor (or XML editor) and find the line:

<node name="logging">

Below is a long list of all logging settings. One of them is:

<entry value="INFO" type="String" key=".level"/>

Which says: INFO debug level for all the code. This level gives you very little debugging information. Therefore for example your init.properties line --debug=server adds one extra line in there:

<entry value="ALL" type="String" key="tigase.server.level"/>

I think now everything should be clear. You need to add a similar line changing only "key" attribute. If you need to switch logging on for a specific class - tigase.xmpp.XMPPIOService for example, add:

<entry value="ALL" type="String" key="tigase.xmpp.XMPPIOService.level"/>

You can also put there your own package or class name. After you changed the config file you have to restart the server.

Note, don't overdose the debugging or your logs are full of trash you can read.

Importing user data

You can easily copy data between Tigase compatible repositories that is repositories for which there is a database connector. It is not that easy however to import data from an external source. Therefore a simple data import functionality has been added to repository utilities package.

You can access repository utilities through command ./bin/repo.sh or ./scripts/repo.sh depending on whether you use binary package or source distribution.

-h parameter gives you a list of all possible parameters:

./scripts/repo.sh -h

Parameters:
 -h          this help message
 -sc class   source repository class name
 -su uri     source repository init string
 -dc class   destination repository class name
 -du uri     destination repository init string
 -dt string  data content to set/remove in repository
 -u user     user ID, if given all operations are only for that ID
             if you want to add user to AuthRepository parameter must
             in form: "user:password"
 -st         perform simple test on repository
 -at         simple test for adding and removing user
 -cp         copy content from source to destination repository
 -pr         print content of the repository
 -n          data content string is a node string
 -kv         data content string is node/key=value string
 -add        add data content to repository
 -del        delete data content from repository
 ------------
 -roster     check the user roster
 -aeg [true|false]  Allow empty group list for the contact
 -import file  import user data from the file of following format:
         user_jid, password, roser_jid, roster_nick, subscription, group



Note! If you put UserAuthRepository implementation as a class name
      some operation are not allowed and will be silently skipped.
      Have a look at UserAuthRepository to see what operations are
      possible or what operation does make sense.
      Alternatively look for admin tools guide on web site.

The most critical parameters are source repository class name and initialization string. Therefore there are a few example, preset parameters which you can use an example and adjust for your system. If you look inside the repo.sh script you can find at the end of the script following lines:

XML_REP="-sc tigase.db.xml.XMLRepository -su ../testsuite/user-repository.xml_200k_backup"
MYSQL_REP="-sc tigase.db.jdbc.JDBCRepository -su jdbc:mysql://localhost/tigase?user=root&password=mypass"
PGSQL_REP="-sc tigase.db.jdbc.JDBCRepository -su jdbc:postgresql://localhost/tigase?user=tigase"

java $D -cp $CP tigase.util.RepositoryUtils $MYSQL_REP $*

You can see that the source repository has been set to MySQL database with tigase as the database name, root the database user and mypass the user password.

You can adjust these settings for your system.

Now to import data to your repository simply execute the command:

./bin/repo.sh -import import-file.txt

Note, the import function is available from b895

The format of the import file is very simple. This is a flat file with comma separated values:
jid,password,roster_jid,roster_nick,subscriptio,group
To create such a file from MySQL database you have to execute command like this one:

SELECT a, b, c, d INTO OUTFILE 'import-file.txt' 
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n' 
FROM test_table;

Prepare the MySQL database for the Tigase server

This guide describes how to prepare the MySQL database for connecting the Tigase server to it.

Basic setup

The MySQL database can be prepared in many ways. Most of Linux distributions contain tools which allow you to go through all steps from the shell command line. To make sure, however it works on all platforms the same way I show first how to do it under MySQL command line client.

Configuring from MySQL command line tool

Run the MySQL command line client in either Linux or MS Windows environment and enter following instructions:

  1. Create the database for the Tigase server:
    mysql> create database tigasedb;
    
  2. Add the tigase_user user and grant him access to the tigasedb database. Depending on how you plan to connect to the database (locally or over the network) use one of following commands or all if you are not sure:
    Grant access to tigase_user connecting from any network address.

    mysql> GRANT ALL ON tigasedb.* TO tigase_user@'%'
                    IDENTIFIED BY 'tigase_passwd';
    

    Grant access to tigase_user connecting from localhost.

    mysql> GRANT ALL ON tigasedb.* TO tigase_user@'localhost'
                    IDENTIFIED BY 'tigase_passwd';
    

    Grant access to tigase_user connecting from local machine only.

    mysql> GRANT ALL ON tigasedb.* TO tigase_user
                    IDENTIFIED BY 'tigase_passwd';
    

    For the Tigase server version 4.x additional permissions must be granted for the database user:

    mysql> GRANT SELECT, INSERT, UPDATE ON mysql.proc TO 'tigase_user'@'localhost';
    mysql> GRANT SELECT, INSERT, UPDATE ON mysql.proc TO 'tigase_user'@'%';
    mysql> GRANT SELECT, INSERT, UPDATE ON mysql.proc TO 'tigase_user';
    
    

    And now you can update user permission changes in the database:

    mysql> FLUSH PRIVILEGES;
    
  3. Load database schema to initialize the Tigase server database space. First, switch to the database you have just created:
    mysql> use tigasedb;
    

    Assuming you run the mysql client in Linux from the Tigase installation directory. If you run the Tigase server all versions below 4.0:

    mysql> source database/mysql-schema.sql;
    

    For the Tigase server version 4.x you have to use proper schema version:

    mysql> source database/mysql-schema-4.sql;
    

    On Windows you have probably to enter the full path:

    mysql> source c:/Program Files/Tigase/database/mysql-schema.sql;
    

    The initialization schema file should be also available locally in database/ directory of your Tigase installation.

Configuring from the Linux shell command line

Follow steps below to prepare the MySQL database:

  1. Create the database space for the Tigase server:
    mysqladmin -p create tigasedb
    
  2. Add the tigase_user user and grant him access to the tigasedb database. Depending on how you plan to connect to the database (locally or over the network) use one of following commands or all if you are not sure:
    Grant access to tigase_user connecting from any network address.

    echo "GRANT ALL ON tigasedb.* TO tigase_user@'%' \
                    IDENTIFIED BY 'tigase_passwd'; \
                    FLUSH PRIVILEGES;" | mysql -u root -pdbpass mysql
    

    Grant access to tigase_user connecting from localhost.

    echo "GRANT ALL ON tigasedb.* TO tigase_user@'localhost' \
                    IDENTIFIED BY 'tigase_passwd'; \
                    FLUSH PRIVILEGES;" | mysql -u root -pdbpass mysql
    

    Grant access to tigase_user connecting from local machine only.

    echo "GRANT ALL ON tigasedb.* TO tigase_user \
                    IDENTIFIED BY 'tigase_passwd'; \
                    FLUSH PRIVILEGES;" | mysql -u root -pdbpass mysql
    
  3. Load database schema to initialize the Tigase server (version below 4.0) database space:
    mysql -u dbuser -p tigasedb < mysql-schema.sql
    

    For the Tigase server version 4.0 and later:

    mysql -u dbuser -p tigasedb < mysql-schema-4.sql
    

    The initialization schema file should be also available locally in database/ directory of your Tigase installation.

 

Server certificate

To allow secure connections through SSL or TLS channel you need SSL certificate.

The main purpose of SSL certificate is to provide connecting entity with a proof of identity of your server. Significant role in proving identity of your server plays trusted third party - usually the issuer of the certificate.

Certificate issued by trusted third party usually cost you a money. You can also use self signed certificate which works as well but gives authentication warning on client software at the connecting time.

Tigase server binary package and sources repository contain so called "dummy" certificate which doesn't refer to any real site name. This certificate is temporary. Should be used only for initial testing of your server. It should be replaced with real one as soon as possible. By real certificate I mean either self signed certificate or issued by trusted third party organization.

Here are instructions how to install real certificate for Tigase server.

Please note! You have to use keytool program included in JDK-1.6 or later version. The utility included in earlier versions can not import third party signed certificates correctly.

Self signed certificate

If you don't have third party signed certificate you should generate self-signed certificate.

Some clients don't works correctly with DSA keys, so we need to use RSA algorithm. To generate private and public keypair you should use keytool:

keytool -genkey -alias yourdomain -keystore rsa-keystore \
    -keyalg RSA -sigalg MD5withRSA

Where yourdomain is a domain part of JIDs on your Jabber/XMPP server. If you want to have TLS support for virtual domains you have to create certificate for each virtual domain. If you have just one domain or for some reason you have to use one certificate for all domains use default as an alias.

Now, enter the secret password to protect keystore:

Enter keystore password: 123456

The keytool asks several questions about certificate data. First question is very important! You must enter a hostname of your XMPP server!!

What is your first and last name?
  [Unknown]: jabber.myserver.org
What is the name of your organizational unit?
  [Unknown]:
What is the name of your organization?
  [Unknown]:
What is the name of your City or Locality?
  [Unknown]:
What is the name of your State or Province?
  [Unknown]:
What is the two-letter country code for this unit?
  [Unknown]:
Is CN=jabber.myserver.org, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
  [no]: yes

In last step you can enter password for key. At the moment different password for keystore and key is not supported so you have to enter the same password here as for keystore.

Enter key password for <mykey>
             (RETURN if same as keystore password):

Now you have to copy file rsa-keystore to directory certs/ in your tigase server installation. The file could also be installed in different location but then corrections to config file are required. Refer to configuration documentation for details.

Cerificate from CA

If you don't have third-party signed certificate yet but you want to have one you could obtain it from cacert.org for free.

First, you have to generate Certificate Request:

keytool -certreq -alias yourdomain -keystore rsa-keystore

Where yourdomain is a domain name for which this certificate is generated. If you need support for multiple virtual domains you need to have certificate for each domain separately and assign proper alias to certificate. If you have just one domain or for some reason you have to use one certificate for all domains use default as an alias.

Keytool generates the request:

-----BEGIN NEW CERTIFICATE REQUEST-----
MIIBrzCCARgCAQAwbzEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UE
BxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjETMBEGA1UEAxMK
c2VydmVyLm9yZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAs73Y70725OcG0j4kpCfDX59e
qhz2gdGOO0LyMO7rm4m+ZCenq8E88M0RJ8/LV/7q0mtOAzbI8dtXZnmJ74xihCH8ZTFpVDMyFWgk
WCj2kz+IUD9vWt6i1UepSkr1a/jYmVMN3RSaoS+j+QLBsJ4rWeOHgIdbiF5tnMhoZMXU//0CAwEA
AaAAMA0GCSqGSIb3DQEBBAUAA4GBAHY5r9rftqiKESbbkCcfVhvnUqN4aMTC8/zXWwzBX8guC0kd
H46+p6eizwJg6p+h6rqShG2OqXCPrJzO3buHr1jEWRTlB8l5CM53L/xq61nYuaSf5R7Vv/RX2+aD
JyoBqYIoSUED0+Sjhej0SUPTOdpA/bfnqdfdtckday4vsLPC
-----END NEW CERTIFICATE REQUEST-----

Now send the request to your CA. CA issues a signed certificate and send it to you. It may may look like:

-----BEGIN CERTIFICATE-----
MIICUDCCAbkCBEUqAK0wDQYJKoZIhvcNAQEEBQAwbzEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UE
CBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMH
VW5rbm93bjETMBEGA1UEAxMKc2VydmVyLm9yZzAeFw0wNjEwMDkwNzU2MjlaFw0wNzAxMDcwNzU2
MjlaMG8xEDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vua25v
d24xEDAOBgNVBAoTB1Vua25vd24xEDAOBgNVBAsTB1Vua25vd24xEzARBgNVBAMTCnNlcnZlci5v
cmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALO92O9O9uTnBtI+JKQnw1+fXqoc9oHRjjtC
8jDu65uJvmQnp6vBPPDNESfPy1f+6tJrTgM2yPHbV2Z5ie+MYoQh/GUxaVQzMhVoJFgo9pM/iFA/
b1reotVHqUpK9Wv42JlTDd0UmqEvo/kCwbCeK1njh4CHW4hebZzIaGTF1P/9AgMBAAEwDQYJKoZI
hvcNAQEEBQADgYEAQqRPdkbc/pdDcPIWOThn2XPp0gitPkXq89ZM1mb0Pib1OISj9ekjqhEZz0UA
cI6g1XttpY6hKi6Gg+mRbwiHNVebkDLamE2UIcVJ1wBtowYeOcV1CcLnlj91ScMKNhfD5ebQL+be
tWWrJX3ep+80kF/NdVkc7htGOhLebopp8SQ=
-----END CERTIFICATE-----

You should save the Certificate to disk file.

If you already have third-party sgined certificate you have to import it with keytool program to server certificate storage.

Note! You must have a root CA certificate!!! You can download the cert from CA (ie.: root.crt) and import:

keytool -import -keystore rsa-keystore -file root.crt \
    -alias root

Last step is import Certificate to your keystore:

keytool -import -alias yourdomain -keystore rsa-keystore \
    -file your-certificate.cer

Where yourdomain is a domain name for which this certificate has been generated. If you need support for multiple virtual domains you have to import certificate for each domain separately and assign proper alias to certificate. If you have just one domain or for some reason you have to use one certificate for all domains use default as an alias.

It's also good to import root CA certificate to this keystore. You must find it on CA website.

keytool -import -keystore rsa-keystore -file rootCA.cer

It may also happen that you have generated certreq using openssl for use in other services like WWW. In such case you may have your private key and certificate in separate files. Let's say private key is in ssl.key file and certificate is in ssl.crt file. To put them together use following command:

openssl pkcs12 -export -inkey ssl.key -in ssl.crt \
    -out mycert.pfx -name "default"

And now you can load certificate with private key to your keystore:

keytool -importkeystore -srckeystore mycert.pfx \
    -srcstoretype pkcs12 -destkeystore rsa-keystore \
    -srcalias default -destalias yourdomain \
    -destkeypass your_keystore_pass

Note! Please note -destkeypass parametr. Your keys password must be the same as keystore password. Otherwise it won't work.

Now you have to copy file rsa-keystore to directory certs/ in your tigase server installation. The file could also be installed in different location but then corrections to config file are required. Refer to configuration documentation for details.

The final note - don't forget to modify tigase server configuration file and set proper password for your keystore.

StanzaSender

This is a component which make it easier to integrate Jabber/XMPP server with other, third-party tools.

It simply allows you to send stanzas from your application without implementing any Jabber/XMPP specific code. The component regularly reads specified data source for XMPP packets to send. The data source can be an SQL database, directory on your filesystem or anything you might want.

If you have Web application for example which you want to send notifications of any event to selected users you can install StanzaSender component on your Tigase server. It will help you to easily distribute your messages to end-users.

How it works

The module itself doesn't do anything. It just schedules tasks and sends stanzas which come from... it doesn't know. To do actual work of retrieving stanzas from data source the component uses tasks.

In theory the task can retrieve XMPP packets for sending from any location or may just generate stanzas on its own.

In practise there are 2 tasks already implemented and ready to use. You can treat them as a sample code for implementation of your own tasks customised for your specific needs or you can just use these tasks as they are.

The tasks which are available are:

  • FileTask retrieving stanzas from directory in file system.
  • JDBCTask retrieving stanzas from SQL database.

FileTask

FileTask implements tasks for cyclic retrieving stanzas from a directory and sending them to the StanzaHandler object.

It looks for any new stanza to send. Any single file can contain only single stanza to send and any entry in database table can also contain only single stanza to send. File on hard disk and record in database is deleted after it is read.

Any file in given directory is treated the same way - Tigase assumes it contains valid XML data with XMPP stanza to send. You can however set in configuration, using wildchars which files contain stanzas. All stanzas must contain complete data including correct "from" and "to" attributes.

By default it looks for *.stanza files in /var/spool/jabber/ folder but you can specify different directory name in initialization string. Sample initialization strings:
/var/spool/jabber/*.stanza
/var/spool/jabber/*
The last is equal to:
/var/spool/jabber/
Note the last forward slash '/' is required in such case if the last element of the path is a directory.

Please note! Tigase must have writing permissions for this directory, otherwise it may not function properly.

JDBCTask

JDBCTask implements tasks for cyclic retrieving stanzas from database and sending them to the StanzaHandler object.

Database table format:

  • id - numerical unique record indetifier.
  • stanza - text field containing valid XML data with XMPP stanza to send.

Any record in this table is treated the same way - Tigase assmes it contains valid XML data with XMPP stanza to send. No other data are allowed in this table. All stanzas must be complete including correct "from" and "to" attriutes.

By default it looks for stanzas in xmpp_stanza table but you can specify different table name in connection string. Sample connection string:
jdbc:mysql://localhost/tigasedb?user=tigase&
password=pass&table=xmpp_stanza

Please note the last parameter which is specific to JDBCTask. You can specify the table name which stores stanzas for sending. If omitted default value is: xmpp_stanza.

Configuration

It is Tigase component so the configuration is similar to configuration of all other components. The simplest way to get the settings for StanzaSender is by generating configuration with all possible components. To do this you have to run Tigase server with --gen-config-all parameter set.

By default this component name is ssend and here is a content of the configuration file for StanzaSender:

It is one of msg-receivers:

<entry type="String[]" key="id-names">
  ...
  <item value="ssend"/>
</entry>

To activate the component and specify class name for it following entries has been added:

<entry value="true" type="Boolean" key="ssend.active"/>
<entry value="tigase.server.ssender.StanzaSender" type="String" key="ssend.class"/>

And the main settings section for the component:

<component name="ssend">
  <map>
   <entry value="10" type="Long" key="default-interval"/>
   <entry value="1000" type="Integer" key="max-queue-size"/>
   <entry type="String[]" key="stanza-listeners">
    <item value="jdbc"/>
    <item value="file"/>
   </entry>
  </map>
  <node name="file">
   <map>
    <entry value="true" type="Boolean" key="active"/>
    <entry value="tigase.server.ssender.FileTask" type="String" key="class-name"/>
    <entry value="%2Fvar%2Fspool%2Fjabber%2F*.stanza" type="String" key="init-string"/>
    <entry value="10" type="Long" key="interval"/>
   </map>
  </node>
  <node name="jdbc">
   <map>
    <entry value="true" type="Boolean" key="active"/>
    <entry value="tigase.server.ssender.JDBCTask" type="String" key="class-name"/>
    <entry value="jdbc%3Amysql%3A%2F%2Flocalhost%2Ftigase%3Fuser%3Dtigase%26password%3Dmypass%26table%3Dxmpp_stanza" type="String" key="init-string"/>
    <entry value="10" type="Long" key="interval"/>
   </map>
  </node>
 </component>

I think most of parameters should be pretty clear but some may need a little explanation. General StanzaSender parameters:

  • default-interval number which specifies in seconds how often should the task look in data source for new packets to send.
  • max-queue-size is a number which specifies internal packets queue size. This is used to prevent the component from consume all the memory for data in case the component can not process them.
  • stanza-listeners is a list of task names to load. Each task can read XMPP packets to send from different data source. You can load as many listeners (tasks) as you need. Each task must read stanzas from different data source.

Each task has own, separate parameters list. For each task from the stanza-listeners list there is a separate section with parameters for each task:

  • active boolean switch allowing you to turn on/off the task without removing configuration completely.
  • class-name Java class name which implements the task. This class must extend tigase.server.ssender.SenderTask and it is loaded at runtime.
  • init-string is kind of data source connection string. For database it is just database connection string, for file system this is just a directory name. It may be even different for different tasks. The 2 tasks already implemented have some specific features: FileTask allows you to use wild-chars in directory/ file name specification and JDBCTask allows you to specify additional parameter at the end of JDBC connection string - database table name. For specific examples look at above config sections.
  • interval is a number which allows you to specify different interval in seconds for checking data source for each task.

Tigase and PyMSN-t transport

Any Jabber server and any transport connect with each other usually through external component protocol (XEP-0114). So all you need to do is to correctly prepare configuration for this protocol on both sides.

Continue reading to learn how to setup Tigase and PyMSN for working together...

There are a few basic parameters to set for this protocol:

  • PORT number - this is standard thing for any TCP/IP connection. Usually the port number should be above 1024 and for PyMSN-t transport it is usually 5347.
  • IP address - again, standard thing for any TCP/IP connection. If both applications - Jabber server and transport run on the same machine the IP address should be 127.0.0.1.
  • SECRET - this is kind of connection password. Transport connects to the Jabber server and authenticates itself using this password. So no other, unauthorised transport can connect to the Jabber server. For our guide let the password be just secret.
  • Transport ID - is an ID in Jabber network. Let's say we want to setup transport for MSN for the server tigase.org. Transport ID can be: msn.tigase.org. It could be also: anything.tigase.org but this name while still valid would be confusing for users and my suggestion is to avoid confusing names.
    Note! Transport ID should resolve to correct IP address. For your tests you can add the ID to /etc/hosts file.

Here is side by side configuration for both applications: PyMSN-t and Tigase to make them work together. I have setup both services on my laptop which hostname is test-d. To make sure both test-d and msn.test-d resolve to correct IP address I am adding entry to /etc/hosts file:

## In your case the IP address should be probably different. 
192.168.0.13    test-d            msn.test-d

Tigase server connects to MySQL database (or built-in XMLBD for simpler configuration variant).

I am not going to setup PyMSN-t to run in background as a system service. This is specific to the system you use and is covered in transport documentation and you operating system. Most of systems have own scripts to start services so I would recommend to use them. Here we just run it in foreground with full logging switched on to the console to make it easier track what happens.

PyMSN-t - /etc/jabber/pymsn-t.xml file Tigase - etc/tigase.conf file
<pymsnt>
  <!-- The JabberID of the transport -->
  <jid>msn.test-d</jid>
  <!-- The public IP or DNS name of the machine
    the transport is running on -->
  <host>test-d</host>
  <!-- The location of the PID file, relative
    to the PyMSNt directory -->
  <pid>/var/run/jabber/pymsn-t.pid</pid>
  <!-- If set, the transport will background
    itself when run, we don't want to do this right
    now. -->
  <!-- <background/> -->
  <!-- The IP address of the main Jabber server
    to connect to -->
  <mainServer>127.0.0.1</mainServer>
  <!-- The TCP port to connect to the Jabber
    server on (this is the default for Jabberd2) -->
  <port>5347</port>
  <!-- The authentication token to use when
    connecting to the Jabber server -->
  <secret>secret</secret>
  <lang>en</lang>
  <website>http://test-d/</website>
  <allowRegister/>
  <getAllAvatars/>
  <!-- Please give the port to listen for Jabber
    socks5 transfers on. Note the standard port number
    set here is 8010. This port
    however is in use on my machine so this is why 
    I had to set it to different value.-->
  <ftJabberPort>8014</ftJabberPort>
  <admins>
    <jid>tus@test-d</jid>
  </admins>
  <!-- The logging level
    0 -> No logging
    1 -> Log tracebacks
    2 -> Log tracebacks, warnings and errors
    3 -> Log everything -->
  <debugLevel>3</debugLevel>
  <!-- The file to log to. Leave this disabled
    for stdout -->
  <!-- <debugFile>debug.log</debugFile> -->
</pymsnt>
You may consider to remove 2 last lines from TIGASE_OPTIONS variable to not use MySQL for now. Tigase will then use internal XMLDB which doesn't need any special setup. (Just remember to leave closing double quotes...)

ENC="-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"
DRV="-Djdbc.drivers=com.mysql.jdbc.Driver"
CLASSPATH="${CLASSPATH}:libs/jdbc-mysql.jar"
JAVA_OPTIONS="${ENC} ${DRV} -server -Xms100M -Xmx100M "
TIGASE_CONFIG="etc/tigase-mysql.xml"
## All TIGASE_OPTIONS settings must be in single line
## They are split to make them more readable
TIGASE_OPTIONS="--gen-config-all --admins \"tus@test-d\"
 --virt-hosts test-d,localhost --debug server
 --ext-comp \"test-d,msn.test-d,5347,secret,plain,accept\"
 --user-db mysql --user-db-uri
 \"jdbc:mysql://localhost/tigase?user=tigase&password=mypass\" "
PyMSN-t - run command Tigase - run command
python /usr/lib/python2.4/site-packages/pymsn-t/pymsn-t.py -c /etc/jabber/pymsn-t.xml



Note! the full path to PyMSN-t config file is important.

./bin/tigase.sh start etc/tigase.conf
PyMSN-t - expected output Tigase - expected output
A few last lines should look like:

[2007-05-07 13:00:39] Starting factory <twisted.xish.xmlstream.XmlStreamFactory instance at 0xb7ce80ac>
[2007-05-07 13:00:39] <twisted.internet.tcp.Connector instance at 0xb7ceb24c> will retry in 2 seconds
[2007-05-07 13:00:39] Stopping factory <twisted.xish.xmlstream.XmlStreamFactory instance at 0xb7ce80ac>
[2007-05-07 13:00:41] Starting factory <twisted.xish.xmlstream.XmlStreamFactory instance at 0xb7ce80ac>
[2007-05-07 13:00:41] <twisted.internet.tcp.Connector instance at 0xb7ceb24c> will retry in 5 seconds
[2007-05-07 13:00:41] Stopping factory <twisted.xish.xmlstream.XmlStreamFactory instance at 0xb7ce80ac>
[2007-05-07 13:00:46] Starting factory <twisted.xish.xmlstream.XmlStreamFactory instance at 0xb7ce80ac>
[2007-05-07 13:00:46] <twisted.internet.tcp.Connector instance at 0xb7ceb24c> will retry in 15 seconds
[2007-05-07 13:00:46] Stopping factory <twisted.xish.xmlstream.XmlStreamFactory instance at 0xb7ce80ac>

And PyMSN should continue to print such lines until it successfully connects to the Tigase server. When it happens following lines should be printed:

[2007-05-07 13:29:04] Starting factory <twisted.xish.xmlstream.XmlStreamFactory instance at 0xb7cf00ac>
[2007-05-07 13:29:04] INFO ::  ::  :: componentConnected :: PyTransport :: {'xmlstream': <twisted.xish.xmlstream.XmlStream instance at 0xb7d0feac>, 'self': 'instance'}
To see the log output from Tigase server execute following command:

tail -f logs/tigase-console.log

After transport connects to Tigase server you should see lines like:

2007-05-07 12:29:05  ComponentConnectionManager.processHandshake() FINE: Connected to: msn.test-d
2007-05-07 12:29:05  ComponentConnectionManager.updateServiceDiscovery() FINEST: Modifing service-discovery info: <item name="XEP-0114 connected" jid="msn.test-d"/>

Note! There was a bug in jabber:iq:register plugin which caused problems with registering account in transport. Please use build 432 or later.

Two or more SessionManagers

In the most cases you use just one SessionManager object for your Tigase server installation. A single SM can handle multiple virtual domains with separate SSL certificates for each domain.

Sometimes, however you need very different configuration for each domain. For example you wish to use a separate database for a selected domain or you need a different set of plugins for each domain. For one domain you might want to allow user registration via XMPP and for another you might want to disable this feature. In such a case you need to load more than one session manager.

This is generally not a problem. You just need to add another component in the configuration and adjust default settings.

The question is now how Tigase server knows to which session manager it has to forward packets received from the network. Mind, there is only one component responsible for handling client connections. So it needs to know somehow which session manager is receiver for certain packet. Of course you set domain names in session manager too. But that is not enough. Tigase server supports cluster mode configuration where session manager can be running on a separate machine. So packet routings rules are not so simple to look at the domain name only. Therefore client connection manager (c2s) must know where is located the session manager responsible for handling the packet received from the network.

To solve the problem routings concept has been introduced. You can define packet routings based on the domain name set during XMPP stream initialization. Each time c2s component receives packet from the network it tries to resolve destination component for the packet based on the current routings table. If you look in you server XML configuration file and search for c2s configuration section you can find routings node. Default configuration for routings table is quite simple. Just a single regular expression:

   <node name="routings">
    <map>
     <entry key=".+" type="String" value="sess-man%40tigase.org"/>
     <entry key="multi-mode" type="Boolean" value="true"/>
    </map>
   </node>

As you can see this routings table forwards all packets to a single destination - session manager located on the tigase.org server.

Let's say we have now two session managers each of them is responsible for a separate domain.sm1@tigase.org handles requests for tigase.org and sm2@tigase.net handles requests for domain tigase.net. So let's modify our default configuration to properly spread the traffic between these two sessiona managers:

   <node name="routings">
    <map>
     <entry key="tigase.org" type="String" value="sm1%40tigase.org"/>
     <entry key="tigase.net" type="String" value="sm2%40tigase.net"/>
     <entry key="multi-mode" type="Boolean" value="true"/>
    </map>
   </node>

Please remember that a key is a regular expression in Java style: Pattern.html. You can match more than a single domain with the key, for example: tigase.+ to match all domains starting with tigase. The expression, however won't match domain: xmpp.tigase.org. To match this domain the expression would need to be: .+tigase.+.

Drupal authentication added

Well it is authentication against Drupal database at the moment. So it is not full integration with Drupal 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 Drupal database based authorization is located in tigase.db.jdbc.DrupalAuth class. Although this class is capable of adding new user 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. Function for adding new users is implemented only to ease user accounts migration from different repository type from earlier Tigase server installation.

The idea 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 Jabber/XMPP even if user provides valid password.

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

Tigase Server version 4.x

Administration manuals and guides for the Tigase server version 4.x line.

Configuration

The main and actually the only configuration for the Tigase server is kept in the XML file. Let's call it tigase.xml for further discussion.

When the user tries to setup the client for the first time he comes across 2 other configuration files: tigase.conf and init.properties which might be confusing. Here is a brief explanation what all those files are about and in other sections you can learn all the details needed to configure the server.

  1. tigase.xml is the only Tigase server configuration file. It stores all the runtime settings and if it is missing the server generates a new file with whole configuration with some default settings + settings read from the init.properties file. You may edit the file manually to adjust settings but this is not recommended as manual editing the XML is error prone. Another way of changing this file and changing the configuration is to use ad-hoc commands which allow you to modify configuration at run-time and cause updating the XML file too. Ad-hoc commands method is not polished yet thus it is also not recommended. The safest way to tweak server runtime parameters is to put them in the init.properties file.
  2. init.properties file is a simple text file with server parameters in form: key = value. When the XML configuration file is missing the Tigase server reads init.properties file and uses parameters found there as defaults for generation of the XML file. Therefore if you change the init.properties file you normally have to stop the server, remove the XML file and start the server again. All the settings from the init.properties are read and applied to the XML configuration. The properties file is easy to read and very safe to modify. At the moment this is the recommended way change the server configuration.
  3. tigase.conf is the Tigase server startup configuration. It is actually not used by the server itself. It rather contains operating system settings and environment parameters to correctly run the Java Virtual Machine. It is only useful on the unix-like systems with Bash shell. If you run the server on MS Windows systems tigase.bat and wrapper.conf files are used instead. The tigase.conf file is read and loaded by the scripts/tigase.sh shell script which also scans the operating system environment for Java VM and other tools needed.

 

Configuring the Tigase server to load a component

A detailed description of all the configuration options is in the init.properties guide where you can also find information described below and much more. Purpose of this document however is to give you a quite and brief information how to load a component into the Tigase server without need to dig through all the details.

I will show how to load 2 components into the Tigase server using configuration in the init.properties file: MUC and PubSub. Please remember, every time you change something in the init.properties file you have to remove the XML configuration file in order to force the server to regenerate the main configuration which is stored in XML file.

The first thing you need is the component implementation. Component implementation is a class or set of classes extending tigase.server.AbstractMessageReceiver. What you need to do is just putting the jar file in the libs/ directory in the Tigase server installation. Then the Tigase server will find all classes automatically at the startup time.

Next step is to tell the server what components to load, how to name them and optionally give some extra parameters. To do so please open the init.properties file you use in your installation. It might be init-mysql.properties or init-pgsql.properties or even your own properties file.

Let's say you want to add just PubSub for now. All you need to do is adding just 2 lines to the properties file:

--comp-name-1=pubsub
--comp-class-1=tigase.pubsub.PubSubClusterComponent

 They mean: the first component name is 'pubsub' and the main class for this component is: 'tigase.pubsub.PubSubClusterComponent. It doesn't really matter what the component name is the only requirement is that it must be unique among other components names. It does also help to give it a name which means something thus 'pubsub' is a good name for a 'PubSub' component but it would be a bad name for the 'MUC' component.

We can of course add more components even PubSub components to the same server. Each of them would need to have a different name then. For example:

--comp-name-2=pubsub-priv
--comp-class-2=tigase.pubsub.PubSubClusterComponent

Which is needed in really rare cases.

Normally, however we want to load few different components like PubSub, MUC, MSN Transport and so on.... Therefore instead of the above second PubSub we can load the MUC component:

--comp-name-2=muc
--comp-class-2=tigase.muc.MUCService

Again! Don't forget to remove your XML config file before restarting the server.

Custom authentication connectors

Tigase server offers you quite a few authentication connectors which allow you to connect to almost any SQL database for user authentication data and share user accounts between the XMPP server and any different system. This feature makes it possible to integrate the Tigase server with other systems without any development effort and without any coding.

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

The first thing to know is that the Tigase server always opens 2 separate connections to the database. One connection is for user login data and another 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 the Tigase server keeps user data in it's own database and only login data are retrieved from the external database.

At the moment the Tigase server 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 the '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 the Tigase has predefined short names for the most common connectors but you can always use the class name if you know it. And 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 also 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 external system. User accounts are added without notifying the Tigase server. Then, when the user logins 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 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 customize you authentication connector by writing your own queries or stored procedures please have a look at 2 following guides: Tigase Auth guide and Tigase Custom Auth guide.

init.properties

init.properties is a little bit extended version of the Java properties file with (key, value) pairs.

Comment line has it's first non-white space ASCII character either '#' or '!'

The key starts with first non-white space ASCII character and ends on either first white space ASCII character or either of '=' or ':'. Therefore if your key contains any of '=', ':' or white space characters you have to escape them with backslash '\': \: or \=.

All of examples below specify 'vhosts' as a key and 'test-a, test-b, test-c' as a value:

vhosts=test-a, test-b, test-c
vhosts : test-a, test-b, test-c
     vhosts     =     test-a, test-b, test-c

Normally you can just copy any property from the XML file to the init.properties file and assign other than a default value which will be used the next time XML file is generated. Let's say we have following XML file section:

<component name="bosh">
  <node name="5280">
   <map       />
   <node name="tls">
    <map>
     <entry type="String" key="allow-invalid-certs" value="false"       />
    </map>
   </node>
  </node>
</component>

To set the default value for this parameters in the init.properties file you need to assign a value to the key. The key consists of the component name, all node names and the key: 'bosh/5280/tls/allow-invalid-certs' and the value is simply 'false'. So in your init.properties file you simply put following line:

bosh/5280/tls/allow-invalid-certs = false 

If you look closer in inside the XML file you can see that each parameter has a 'key', 'value' and a 'type'. If you put the parameter in the init.properties file you must specify the type of the parameter as well. Otherwise the property won't be loaded. The default type is 'String' therefore for string properties you don't have to specify the type. For all others the type must be set. The type is set by appending [T] at the end of the key name where 'T' indicates the type. Possible types are:

  • [S] (or nothing) - Characters string: 'abcdef'
  • [s] - String array: 'abcdef, ghaijk, lmnopq'
  • [B] - Boolean: 'true' or 'false'
  • [b] - Boolean array: 'true, true, false'
  • [L] - Long number: 1234567890
  • [l] - Long array: '12334, 45435, 45645'
  • [I] - Integer number: 123456
  • [i] - Integer array: '123, 456, 678'

Let's say we want to set some timeout which is a long type property to value 60:

ssender/games-list-updater/interval[L]=60

Except the XML parameters you can inject during the configuration generation time there is a bunch of parameters which have broader meaning than just one property. Some of them affect many configuration settings or can generate whole sections in the XML file. Most of them starts with '--' - double hyphen. Here is a list of all those parameters with description:

  • 'config-type = --gen-config-def' - probably the only such a property not starting with double hyphen. It sets the server type and determines what components are included in the generated XML file. Possible values are listed below:
    • '--gen-config-all' - creating configuration file with all available components. That is: session manager, client-to-server connection manager, server-to-server connection manager, one external component connection manager, stanza sender and stanza receiver.
    • '--gen-config-def' - creating default configuration file. That is configuration which is most likely needed for a typical installation. Components included in configuration are: session manager, client-to-server connection manager and server-to-server connection manager.
    • '--gen-config-sm' - creating configuration for instance with session manager and external component only. This is useful for distributed installation where you want to have session manager installed on separate machine and components managing network connections on different machines (one or more). Components included in configuration are: 'sm' and 'ext2s'.
    • '--gen-config-cs' - creating configuration for instance with components managing network connections. This is useful for distributed installation where you want to have session manager installed on separate machine and components managing network connections on different machines (one or more). Components included in configuration are: 'c2s', 's2s', 'ext2s'.
  • '--user-db = db-type' - where 'db-type' can be one of possible values: mysql, pgsql, xml or the class name. For SQL database this is normally: tigase.db.jdbc.JDBCRepository.
  • '--user-db-uri = connection-uri' - where 'connection-uri' is a full resource uri for user repository data source. If you skip this parameter default value is used depending on database type you selected:
    • jdbc:mysql://localhost/tigase?user=root&password=mypass
    • jdbc:postgresql://localhost/tigase?user=tigase
    • user-repository.xml
  • '--auth-db = db-type' - where 'db-type' can be one of possible values: mysql, pgsql, xml, drupal, libresource, tigase-auth and tigase-custom (If omitted 'user-db' settings are used.) or the class name. For SQL database this is normally: tigase.db.jdbc.JDBCRepository.
  • '--auth-db-uri = connection-uri' - where 'connection-uri' is a full resource uri for user repository data source. (If omitted 'user-db-uri' settings are used.)
  • '--ext-comp = connection-string' - possible values: connection string 'localdomain,remotedomain,port,passwd,(plain|ssl),(accept|connect),routing'
    Note: It is also possible to generate configuration for many external components. To do so use '--ext-comp_1 parameters', '--ext-comp_2 parameters' and so on...
  • '--virt-hosts = virtual-hosts-list' - possible values: list of virtual domains to support 'domain1,domain2'. This option causes to use virtual hosts given here instead of default/automatically detected host names.
  • '--admins = admin-accounts-list' - specifies a list of administrator accounts. Possible values: list of admin accounts: 'user1@domain,user2@domain2'
  • '--trusted = trusted-accounts-list' - specifies a list of accounts which are considered as trusted, thus can perform some specific actions on the server. They can execute some commands, send a broadcast message, set MOTD and so on. The configuration is similar to '--adimins' setting.
  • '--test' - this parameter informs that config is generated for test instance, which means that all loggings are turned off
  • '--debug = tigase-package' - you can turn on debugs log for selected tigase package. For example if you want to turn debug logs on for package: tigase.server then you have to put parameter: '--debug server'. If you have any problems with your server the best way to get help from me is to generate configuration with '--debug = server' and run the server. Then from the logs/tigase-console.log log file I can get all information I need to give you a help. More details about server logging and adjusting logging level is described in article Debugging Tigase.
  • '--comp-name-1 = name' - is used to assign name 'name' to the non-standard component which is loaded by the server. It is normally used when you want to load component which is not loaded by the 'config-type' you use. Together with '--comp-class-1' it allows you to load any extra component to your server configuration. Of course you can load more than just one component. Just use '--comp-name-2', '--comp-name-3' and so on... Let's say you want to load the MUC component. You can then put give it a name: 'muc' and the setting would look like:
    --comp-name-1 = muc
  • '--comp-class-1 = class name' - is used to load an extra component to the server. Normally this parameter is used if you want to load a component which is not included in the 'config-type' you use. You can, of course, load more than just one component using parameters: '--comp-class-2', '--comp-class-3' and so on.... Let's say you want to load the MUC component and the class name for the component is: 'tigase.muc.MUCService'. The line in the properties file should look like:
    --comp-class-1 = tigase.muc.MUCService
  • '--cluster-mode = (true|false)' - sets the cluster mode. The default value is 'false' so you can normally skip the parameter if you don't want the server to run in the cluster mode. You can run the server in the cluster mode even if there is only one node running. The performance impact is insignificant and you have the opportunity to connect mode cluster nodes at any time without restarting the server.
  • '--cluster-nodes = list of cluster nodes' - is a comma separated list of the cluster nodes. The node is a full DNS name of the machine running the node. Please note the proper DNS configuration is critical for the cluster to work correctly. Make sure the 'hostname' command returns a full DNS name on each cluster node. Nodes don't have to be in the same network although good network connectivity is also a critical element for an effective cluster performance.
    --cluster-nodes=host-a.domain.com,host-b.domain.com,host-c.domain.com

    All cluster nodes must be connected with each other to maintain user session synchronization and exchange packets between users connected to different nodes. Therefore each cluster node opens a 'cluster port' on which it is listening for connections from different cluster nodes. As there is only one connection between each two nodes the Tigase server has to decide which nodes connects and which has to accept the connection. If you put the same list of cluster nodes in the configuration for all nodes this is not a problem. The Tigase server has a way to find it out and void conflicts. If you however want to add a new node later on, without restarting and changing configuration on old nodes there is no way the old nodes will try to establish a connection to the new node they don't know of. To solve this particular case the next parameter is used.

  • '--cluster-connect-all = (true|false)' - causes the cluster node to open active connections to all nodes listed in the '--cluster-nodes' configuration property. This property should be used only on the node which is added to the live cluster at later time. Normally this new cluster node is not listed in configuration of the existing cluster nodes. This is why they can not open connections the new node. The new node opens connection to all existing nodes instead. False is the default value and you can skip this option if you  want to have it switched off. 
  • '--sm-plugins = list of pluggins' - lists all plugins which should be loaded by the server. Normally you don't have to specify this. Server loads default list of plugins automatically. The default list contains all available plugins. Sometimes however you might want to load only some plugins. Typical use case is when user accounts are managed on your third-party system the Tigase server is integrated with. Then you might not want to allow users to register new accounts via XMPP service. You can then load a list of plugins without the user registration plugin. Another case when you usually have to use this option is when you have your own plugins which replace function of the Tigase default plugins like vCard, roster management, and so on....
  • '--max-queue-size = N' - set internal queues maximum size to a specified value. By default the Tigase sets the queue size depending on the maximum available memory to the Tigase server process. It set's 1000 for each 100MB memory assigned for JVM. This is enough for most use cases. If you have, however extremely busy service with Pubsub or MUC component generating huge number of packets (presence or messages) this size should be equal or bigger to the maximum expected number of packets generated by the component in a single request. Otherwise the Tigase may drop packets which it is unable to process.

 

Startup file for tigase.sh - tigase.conf

Property file name for tigase.sh startup script is a second parameter for the startup script. It can be skipped if environmental variables are set in different place or in different way.

Config file for startup script simply sets number of environment variables with location of required components. Possible variables to set in this file are:

  • JAVA_HOME - location of Java installation home directory. Must be set.
  • TIGASE_HOME - location of Tigase installation home directory. By default script try to find this location by searching directories from the location where the script has been run.
  • TIGASE_CONSOLE_LOG - file to which all console messages will be redirected if server is run in background. By default it will be: TIGASE_HOME/logs/tigase-console.log. If this file/directory is not writable by Tigase process all console messages will be redirected to /dev/null
  • TIGASE_PID location of the file with server PID number. By default it will be TIGASE_HOME/logs/tigase.pid.
  • TIGASE_CONFIG - location of the Tigase server config file. This is main config XML file. Not to be confused with startup script parameters file. If not set script trys to find it in following locations in given order: /etc/conf.d/tigase-server.xml, /etc/tigase-server.xml, /etc/tigase/tigase-server.xml or finally in TIGASE_HOME/etc/tigase-server.xml
  • JAVA_OPTIONS - options for JVM like size of RAM allocated for the JVM, properties and so on.
  • TIGASE_OPTIONS - additional options for Tigase server program. You can tweak here initial parameters for your environment.

Sample file to run Tigase with PostgreSQL database may look like:

ENC="-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"
DRV="-Djdbc.drivers=org.postgresql.Driver"
JAVA_OPTIONS="${ENC} ${DRV} -server -Xms100M -Xmx100M "
CLASSPATH=""
TIGASE_CONFIG="tigase-pgsql.xml"
TIGASE_OPTIONS=" --property-file etc/init.properties "

Please note encoding settings. I have received several requests about encoding problems. JVM by default uses encoding set in operating system environment. XMPP protocol, however uses UTF-8 for all data processing. So the above settings enforces UTF-8 encoding for all operations.

Another significant setting is 'CLASSPATH'. It is intentionally set to empty string. The tigase.sh startup script builds the CLASSPATH on it's own from files found in jars/ and libs/ directories. I advice to set the CLASSPATH to the empty string because the Tigase server scans all available classes to find all components and plugins implementation. If the CLASSPATH contains lots of libraries which are not used anyway it cases long startup time and lots of memory consumption.

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 Custom Authentication Connectors guide.

To make this connector working you have to prepare your database to offer set of stored procedures for the 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 mysql-schema-4-sp.schema for MySQL database and in postgresql-schema-4-sp.schema file for PostgreSQL database. You can also refer to the tables definition files to see how database is organized in our implementation: mysql-schema-4.sql file for MySQL database and 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/logout 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 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 want to define your own queries in the configuration file. The shortest possible description is the following example of the content from init.properties file:

sess-man/auth-repo-params/conn-valid-query=select 1
sess-man/auth-repo-params/init-db-query=update tig_users set online_status = 0
sess-man/auth-repo-params/add-user-query={ call TigAddUserPlainPw(?, ?) }
sess-man/auth-repo-params/del-user-query={ call TigRemoveUser(?) }
sess-man/auth-repo-params/get-password-query=select user_pw from tig_users where user_id = ?
sess-man/auth-repo-params/update-password-query=update tig_users set user_pw = ? where user_id = ?
sess-man/auth-repo-params/user-logout-query=update tig_users, set online_status = online_status - 1 where user_id = ?
sess-man/auth-repo-params/non-sasl-mechs=password,digest
sess-man/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 for unknown reason.

Some queries 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' - Rertieves 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.

    The Tigase server 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. 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 formay in the database.

 

MySQL database schema upgrade for Tigase 4.0

For number of reasons the database schema had to be changed for Tigase server version 4.0. The most important are:

  • Compliance with the XMPP RFC which says that each part of JID may have up to 1023 characters. We store in the database user JIDs without resource name thus the maximum possible size of the user id is 2047. There aren't really JIDs that long yet but we experienced quite long JIDs in a few installations already so we decided to prepare Tigase to accept any JID allowed by RFC.
  • Performance and flexibility - the Tigase server now accesses database using stored procedures. This allows for any database storage format and it doesn't really matter for the Tigase server what is the database schema how data is organized inside. What it needs is just bunch of stored procedures to access the data. This allows for much more flexibility in storing user data as well as much easier integration with third-party systems and also organize data in more efficient way.

Therefore when you run the Tigase server now it may (depending on what exact SVN revision you use) refuse to start if it detects that the database schema is not updated. If it happens just follow steps below to update the database schema and start the server again. Updating of the database schema is very easy and almost fully automated process. Just follow the steps below and you should be able to run new version of the Tigase server in a few minutes or even seconds depending on your database size. It takes around 7 minutes to update database with 200k user accounts on an average machine. Note. Do not update the database schema before the Tigase server tells you to do so. And do a database backup before starting the schema update.

Please note. I have done a few schema upgrades already in a different configurations and here are a few tips which might be useful if something goes wrong:

  1. You really, really have to do the DB backup (database dump) before upgrading. If you don't you might not be able to revert database on your own. Contact me in case of problems.
  2. In case of error: ERROR 1419 (HY000) at line 31 in file: 'database/mysql-schema-4-sp.schema': You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) Restore the database following description found below and run the update again as MySQL super user.
  3. The following error may manifest itself in many ways from the NullPointerException in the Tigase server log file to message like this: User does not have access to metadata required to determine stored procedure parameter types. If rights can not be granted, configure connection with "noAccessToProcedureBodies=true" to have driver generate parameters that represent INOUT strings irregardless of actual parameter types. The best solution to this is to grant proper permissions to this user. Enter the MySQL command line mode as MySQL super user:
     $ mysql -u root -proot_passwd mysql
    mysql> GRANT SELECT, INSERT, UPDATE ON \`mysql\`.\`proc\` TO 'tigase_user'@'localhost';
    mysql> GRANT SELECT, INSERT, UPDATE ON \`mysql\`.\`proc\` TO 'tigase_user'@'%';
    mysql> GRANT SELECT, INSERT, UPDATE ON \`mysql\`.\`proc\` TO 'tigase_user';
    mysql> FLUSH PRIVILEGES;
     $
    

Assumptions:

  1. tigasedb is a database name
  2. tigase_user is a database user name
  3. mypass is database user password

First things first - make a database backup:

mysqldump -u tigase_user -pmypass tigasedb > tigasedb_dump.sql

If you need to restore database for any reason execute following commands:

msyqladmin -u tigase_user -pmypass drop tigasedb
mysqladmin -u tigase_user -pmypass create tigasedb
mysql -u tigase_user -pmypass tigasedb < tigasedb_dump.sql

Note! You may be required to use root user and his password to execute mysqladmin commands. Ok we have the database backup and we know how to restore it. Now we can run schema upgrade script:

mysql -u tigase_user -pmypass tigasedb < database/mysql-schema-upgrade-to-4.sql

The script should generate output like this:

Droping index for user_id column
Resizing user_id column to 2049 characters to comply with RFC
Creating a new index for user_id column for first 765 bytes of the field
Adding sha1_user_id column
Adding user_pw column
Adding last_login column
Adding last_logout column
Adding online_status column
Adding failed_logins column
Adding account_status column
Creating a new index for user_pw column
Creating a new index for last_login column
Creating a new index for last_logout column
Creating a new index for account_status column
Creating a new index for online_status column
Resizing node column to 255 characters
Changing pval column type to mediumtext
Loading stored procedures definitions
Setting passwords encoding in the database
Converting database to a new format
Creating a new index for sha1_user_id column
Setting schema version to 4.0
All done, database ready to use!

 

Virtual components for the cluster mode

Let's assume you have a cluster installation and you want to include a component in  your installation which doesn't support the cluster mode yet. If you put it on all nodes as a separate instances they will work out of sync and overall functionality might be useless. If you put on one node only it will work correctly but it will be visible to users connected to this one node only.

Ideally you would like to have a mechanism to install it on one node and put some redirections on other nodes to forward all packets for this component to a node where this component is working. Redirection on it's own is not enough however because the component must be visible in service discovery list and must be visible somehow to users connected to all nodes.

This is where the virtual components are handy. They are visible to users as a local normal component, they seem to be a real local component but in fact they just forward all requests/packets to a cluster node where the real component is working.

Virtual component is a very lightweight ServerComponent implementation in the Tigase server. It can pretend to be any kind of component and can redirect all packets to a given address. They can mimic native Tigase components as well as third-party components connected over external component protocol (XEP-0114).

Configuration is very simple and straightforward. In fact it is very similar to configuration of any Tigase component. You set a real component name as a name of the component and a vritual component class name to load. Let's say we want to deploy MUC component this way. The MUC component is visible as muc.domain.our in the installation. Thus the name of the component is: muc

--comp-name-1=muc
--comp-class-1=tigase.cluster.VirtualComponent

This is pretty much all you need to load a virtual component. A few other options are needed to point to correct destination addresses for packets forwarding and to set correct service discovery parameters:

muc/redirect-to=muc@cluster-node-with-real-muc.domain.our
muc/disco-name=Multi User Chat
muc/disco-node=
muc/disco-type=text
muc/disco-category=conference
muc/disco-features=http://jabber.org/protocol/muc

That's it.

Virtual Hosts in the Tigase server

The Tigase server supports multiple virtual hosts for a single server installation. This is supported via VHostManager - the new Tigase server component added recently to the implementation. Virtual hosts can be added or removed, enabled or disabled at the server runtime without restarting the service or disrupting normal operation.

This document describes how virtual hosts work in the Tigase server and how to take the most of this feature in your installation.

Virtual hosts property in the GUI installer The simplest and default way to set virtual hosts is the server configuration. You can either edit manually the init.properties file or use the graphical installer/configuration program to set the property. If you want to edit it manually search for '--virt-hosts' property for more detailed description.

Alternatively you can use the GUI installer as shown on the left hand side to set a list of virtual hosts.

This method however has many disadvantages. It requires the server restart after each change, the configuration file is not the best place to store long list of virtual domains and you can not actually set any additional parameters for the domain other than it does exist or not.

There is another way to store and control virtual domains in the Tigase server. They can be put in the database and managed using ad-hoc commands. List of domains can be modified outside the Tigase server through any third-party system or web application and the server reloads the list of when received VHOSTS_RELOAD ad-hoc command.

There are 2 more ad-hoc commands which allow you to add/update and remove virtual hosts via XMPP protocol:

  • VHOSTS_UPDATE - for adding new virtual host or changing parameters of the existing domain
  • VHOSTS_REMOVE - for removing existing virtual domain from the list of the server domains.

By default, both commands cause vhosts list update in the permanent repository. This is however VHostRepository implementation dependent feature and can be changed in your repository implementation.

Commands for virtual domains management can be executed using any XMPP client with a good support for service discovery and ad-hoc commands, for example Psi. Commands are accepted only when they are sent by the service administrator.

Please refer to documents listed below for more detailed information on the following topics:

 

Specification for ad-hoc commands used to manage virtual domains

There are 3 ad-hoc commands for virtual domains management in the Tigase server:

  1. VHOSTS_RELOAD used to reload virtual domains list from the repository (database).
  2. VHOSTS_UPDATE used to add a new virtual domain or update information for existing one.
  3. VHOSTS_REMOVE used to remove an existing virtual host from the running server.

Syntax of the commands follows specification described in the XEP-0050. Extra information required to complete the command is carried as data forms described in the XEP-0004.

All commands are accepted by the server only when send by the installation administrator. If the command is sent from any other account <not-authorized /> error is returned. To grant administrator rights to an account you have to set --admins property in the configuration file.

Commands are sent to 'vhost-man' server component and the 'to' attribute of the stanza must contain a full JID of the VHostManager on the server. The full JID consists of the component name: 'vhost-man' and the local domain, that is domain which is already on the list of virtual domains and is active. Assuming 'existing.domain.com' one of domains already activated for the server installation the JID is: 'vhost-man@existing.domain.com'.

Reloading the domains list from the database

 

In order to reload virtual domains from the permanent repository other than configuration file you have to send VHOSTS_RELOAD ad-hoc command to the VHostManager on the server.

The reload command request is of the form:

<iq type="set" 
    to="vhost-man@existing.domain.com"
    id="aac8a">
  <command xmlns="http://jabber.org/protocol/commands"
           node="VHOSTS_RELOAD" />
</iq>

The server sends a response upon successful completion of the command with current number of virtual domains server by the installation:

<iq from="vhost-man@existing.domain.com"
    type="result" 
    to="cmd-sender-admin@existing.domain.com" 
    id="aac8a">
  <command xmlns="http://jabber.org/protocol/commands"
           status="completed"
           node="VHOSTS_RELOAD">
    <x xmlns="jabber:x:data" type="result">
      <field type="fixed" var="Note">
        <value>Current number of VHosts: 123</value>
      </field>
    </x>
  </command>
</iq>

 If the command is sent from other than admin account the server returns an error:

<iq from="vhost-man@existing.domain.com"
    type="error"
    to="cmd-sender-admin@existing.domain.com"
    id="aac8a">
  <command xmlns="http://jabber.org/protocol/commands"
           node="VHOSTS_RELOAD" />
  <error type="auth" code="401">
    <not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
    <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"
          xml:lang="en">
      You are not authorized for this action.
    </text>
  </error>
</iq>

The response doesn't have any special meaning other then informative for the end-user. The client may ignore response as it is sent after the command has been executed.

Adding a new domain or updating existing one

 

In order to add a new domain or update existing one you have to send an ad-hoc command VHOSTS_UPDATE with at least domain name in the command data form. You can also specify whether the domain is enabled or disabled but this is optional. Future releases may allow for setting additional parameters for the domain: maximum number of user accounts for this domain, anonymous login enabled/disabled for the domain, registration via XMPP enabled/disabled for this domain and some more parameters not specified yet.

The domain add/update command request is of the form:

<iq type="set"
    to="vhost-man@existing.domain.com"
    id="aacba">
<command xmlns="http://jabber.org/protocol/commands" node="VHOSTS_UPDATE">
<x xmlns="jabber:x:data" type="submit"> <field type="text-single" var="VHost"> <value>new-virt.domain.com</value> </field>
<field type="list-single" var="Enabled"> <value>true</value> </field> </x> </command>
</iq>

Please note! Character case in the command field variable names does matter.

Upon successful completion of the command the server sends a response back to the client with information of the existing number of virtual hosts on the server:

<iq from="vhost-man@existing.domain.com"
    type="result"
    to="cmd-sender-admin@existing.domain.com"
    id="aacba">
<command xmlns="http://jabber.org/protocol/commands" status="completed" node="VHOSTS_UPDATE">
<x xmlns="jabber:x:data" type="result"> <field type="fixed" var="Note"> <value>Current number of VHosts: 124</value> </field> </x> </command> </iq>

 

Removing a virtual domain from the server

 

In order to remove a virtual domain you have to send VHOSTS_REMOVE command to the server with the domain name.

The domain remove command is sent by the client:

<iq type="set"
    to="vhost-man@existing.domain.com"
    id="aacba">
<command xmlns="http://jabber.org/protocol/commands" node="VHOSTS_REMOVE">
<x xmlns="jabber:x:data" type="submit">
<field type="text-single" var="VHost"> <value>virt-nn.domain.com</value> </field>
</x>
</command>
</iq>

Upon successful completion of the command the server sends a response back to the client with information of the existing number of virtual hosts on the server:

<iq from="vhost-man@existing.domain.com"
    type="result"
    to="cmd-sender-admin@existing.domain.com"
    id="aacba">
<command xmlns="http://jabber.org/protocol/commands" status="completed" node="VHOSTS_REMOVE">
<x xmlns="jabber:x:data" type="result">
<field type="fixed" var="Note"> <value>Current number of VHosts: 124</value>
</field>
</x>
</command>
</iq>

 

Tigase Server version 3.x

Admin manuals and guides for the Tigase server version 3.x line.

Configuration

This section contains the Tigase server configuration manuals and guides.

Configuration wizards

From the build #247 you can use configuration generators to easily and quickly create configuration file for even complex case.

Tigase configuration is not too easy to understand and maintain. Even with current command line tools you still have to know what the all options are for.

To make it easier for average administrators or people who run the server for the first time or even for those who want to quickly test Tigase server in different scenarios configuration generators have been created. For each generator you can have also a few extra options which allows you to create configuration which you don't need to change for some time.

A few definitions first to make it easier to read the rest:

  • sm - session manager component.
  • c2s - client connection manager component
  • s2s - server connection manager component
  • ext2s - external component connection manager
  • ssender - StanzaSender component

The are 4 generators currently available:

  1. --gen-config-all - creating configuration file with all available components. That is: sm, c2s, s2s, ext2s, ssender.
  2. --gen-config-default - creating default configuration file. That is configuration which is most likely needed for basic installation. Components included in configuration are: sm, c2s, s2s.
  3. --gen-config-sm - creating configuration for instance with session manager and external component only. This is useful for distributed installation where you want to have session manager installed on separate machine and components managing network connections on different machines (one or more). Components included in configuration are: sm and ext2s.
  4. --gen-config-cs - creating configuration for instance with components managing network connections. This is useful for distributed installation where you want to have session manager installed on separate machine and components managing network connections on different machines (one or more). Components included in configuration are: c2s, s2s, ext2s.