YATE as a jabber server



    YATE is in many ways a unique telephone server. He understands SIP-T, is considered the best H323-SIP converter, and also supports most of the OKS-7 (SS7) protocol family. And all this is available under the GPL. On the other hand, the problem is the lack of documentation of the project.

    But I do not want to talk about telephony. Rabbits are not only valuable fur, but Yate can also serve as a jabber server. It's funny that Yate is not listed on xmpp.org/xmpp-software/servers , although support for the jabber server appeared in it back in 2010.

    It's hard to say why you might need to use Yate for jabber if you have ejabberd, Openfire, Prosody, and Tigase. This question is beyond the scope of the article. I just want to introduce you to another option.

    So welcome under cut. (Caution, a lot of letters!) At the same time I will tell you how to fasten authorization in Active Directory.

    We will assume that the reader will cope with the installation on their own . Let's do the setup.

    We indicate the main parameters of the jabber server: the domain listening on sockets, cancel digest authorization (necessary to transfer the password in its original form for authorization in AD).
    Attention! The c2s_plainauthonly option is available only in svn, in version 4.3 it is not.

    jabberserver.conf
    [general]
    domains=mydomain.org
    c2s_plainauthonly=yes; force text password for LDAP auth
    [listener s2s]
    enable=yes
    type=s2s
    port=5269
    [listener c2s]
    enable=yes
    type=c2s
    port=5222
    


    In order not to transmit our password in clear text, you need to enable SSL encryption. To do this, we will indicate in the settings for which domains the ssl certificate should be used. It should be noted that you should not enable the sslcontext = option, which you can see in the default config, since in this case Yate will expect an encrypted connection from the client, while jabber clients usually use the two-stage StartTLS procedure.

    openssl.conf
    [yate]
    certificate=yate.pem
    domains=mydomain.org
    

    How to generate a certificate, I will not tell.

    We configure the authorization and registration module to the database.

    register.conf
    [general]
    user.auth=yes
    user.register=yes
    user.unregister=yes
    engine.timer=yes
    [default]
    account=yate
    [user.auth]
    query=SELECT password FROM users WHERE username='${username}' AND password IS NOT NULL AND password<>''
    result=password
    [user.register]
    query=UPDATE users SET location='${data}', expires=CURRENT_TIMESTAMP + INTERVAL ${expires}+300 second WHERE username='${username}'
    [user.unregister]
    query=UPDATE users SET location=NULL,expires=NULL WHERE expires IS NOT NULL AND username='${username}'
    [engine.timer]
    query=UPDATE users SET location=NULL,expires=NULL WHERE expires IS NOT NULL AND expires<=CURRENT_TIMESTAMP
    


    Database structure for MySQL. You can use Postgres.

    CREATE TABLE `offlinechat` (
      `username` varchar(100) DEFAULT NULL,
      `xml` text,
      `time` int(11) NOT NULL,
      KEY `username` (`username`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    CREATE TABLE `roster` (
      `username` varchar(100) DEFAULT NULL,
      `contact` varchar(100) DEFAULT NULL,
      `name` varchar(100) DEFAULT NULL,
      `groups` varchar(100) DEFAULT NULL,
      `subscription` varchar(100) DEFAULT NULL,
      UNIQUE KEY `uc` (`username`,`contact`),
      KEY `username` (`username`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    CREATE TABLE `users` (
      `username` varchar(100) NOT NULL DEFAULT '',
      `password` varchar(100) DEFAULT NULL,
      `vcard` text,
      `location` varchar(100) DEFAULT NULL,
      `expires` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      PRIMARY KEY (`username`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    


    Configuring the

    mysqldb.conf database connector
    [yate]
    database=yate
    user=yate
    password=yatepass
    


    We configure the vcard function and offline messages.

    jbfeatures.conf
    [general]
    account=yate
    [vcard]
    get=SELECT vcard FROM users WHERE username='${username}'
    set=UPDATE users SET vcard='${vcard}' WHERE username='${username}'
    [offline_chat]
    get=SELECT * FROM offlinechat WHERE username='${username}' ORDER BY time
    add=INSERT INTO offlinechat (username,xml,time) VALUES ('${username}', '${xml}', ${time})
    clear_user=DELETE FROM offlinechat WHERE username='${username}'
    


    Customize the roster.

    subscription.conf
    [general]
    account=yate
    user_roster_load=SELECT users.username, roster.* FROM users LEFT OUTER JOIN roster ON users.username=roster.username WHERE users.username='${username}'
    user_roster_delete=DELETE FROM roster WHERE username='${username}'
    contact_load=SELECT * FROM roster WHERE username='${username}' AND contact='${contact}'
    contact_subscription_set=INSERT roster (username,contact,subscription) VALUES ('${username}','${contact}','${subscription}') ON DUPLICATE KEY UPDATE subscription='${subscription}'
    contact_set=INSERT roster (username,contact,name,groups) VALUES ('${username}','${contact}','${name}','${groups}') ON DUPLICATE KEY UPDATE name='${name}',groups='${groups}'
    contact_set_full=INSERT roster (username,contact,name,groups,subscription) VALUES ('${username}','${contact}','${name}','${groups}','${subscription}') ON DUPLICATE KEY UPDATE name='${name}',groups='${groups}',subscription='${subscription}'
    contact_delete=DELETE FROM roster WHERE username='${username}' AND contact='${contact}'
    

    As you can see, most of the tuning comes down to writing SQL queries. It may seem uncomfortable, but it gives flexibility.

    Now about authorization through Active Directory.
    First, we’ll tweak register.conf so that users are automatically added to the database after successful authorization (but flexibility came in handy!).
    [user.register]
    query=INSERT users (username,location,expires) VALUES ('${username}','${data}',CURRENT_TIMESTAMP + INTERVAL ${expires}+300 second) ON DUPLICATE KEY UPDATE  location='${data}', expires=CURRENT_TIMESTAMP + INTERVAL ${expires}+300 second
    

    Secondly, add some Yate magic. The server core is a system message manager, which Engine exchanges with standard and external modules (there are no fundamental differences). To run an external module in PHP, just write it in the config. Our jabber.php script will intercept the user.auth system message (request for authorization), and process it by accessing AD. The message is intercepted due to the priority of the handler = 40, while the rest of the modules have a priority of 50 or higher, which is less priority.
    extmodule.conf
    [general]
    scripts_dir=/etc/yate/
    [scripts]
    jabber.php=
    


    And finally, the authorization script (module) itself. Please note that it uses the libyate.php library included with the Yate distribution. It should be accessible to the script, so it is best to copy it to the same directory. If the domain controller uses a self-signed certificate, add the line to /etc/openldap/ldap.conf
    TLS_REQCERT never 
    


    jabber.php
    #!/usr/bin/php -q
    type) {
            case "incoming":
                switch ($ev->name) {
                    case "user.auth":
                        if (!isset($ev->params["digest-uri"])) {
                            $username = $ev->params["username"];
                            $username = substr($username,0,strpos($username,'@'));
                            $password = isset($ev->params["response"]) ? $ev->params["response"] : $ev->params["password"];
                            $auth = ad_auth($username, $password);
                            if ($auth) {
                                $ev->retval = $password;
                                $ev->handled = true;
                            }
                        }
                        break;
                }
                $ev->Acknowledge();
                break;
            case "installed":
                Yate::Output("PHP Installed: " . $ev->name);
                break;
            case "uninstalled":
                Yate::Output("PHP Uninstalled: " . $ev->name);
                break;
            default:
                Yate::Output("PHP Event: " . $ev->type);
        }
    }
    Yate::Output("PHP: bye!");
    /* vi: set ts=8 sw=4 sts=4 noet: */
    ?>
    

    According to Paul Chitescu, Yate’s lead developer, must be ready.

    And finally, I have two news, good and bad:
    • Good: YATE can jingle (voice), that is, clients of your jabber server can call each other, for example, using Psi.
    • Bad: YATE does not know how to MUC (Multi User Chat).


    If something is incomprehensible, or does not work, ask questions, I will try to answer.

    Also popular now: