понедельник, 1 марта 2021 г.

Sip-клиент MicroSIP со списком контактов из Active Directory

Когда необходимо использвовать sip-клиент в корпоративной среде, то к нему выдвигается несколько требований, в которых, среди прочего, лёгкость автоматической настройки для разворачивания на компьютеры пользователей и возможность использовния централизованного телефонного справочника, формируемого из данных о пользователях в Active Directory. И лучше всего получить это без лишних материанльных затрат.
По поводу автоматической установки на компьютеры пользователей есть статья на Хабре. Там описан достаточно простой способ разворачивания MicroSIP на компьютеры пользователей, так что изобретать велосипед нет смысла. В этой же заметке будет описано как сформировать единый телефонный справочник для пользователей.

MicroSIP может загружать телефонну книгу через http(s), которая сформирована в виде xml или json, с использованием кодировки utf-8. Список контактов будем формировать как xml-документ, а отдавать его пользователям будет Apache, который уже есть в составе FreePBX Distro, использующегося в качестве ip-атс. Формировать телефонный справочник будет скрипт на python, запускающийся по расписанию. За его основу будет взят механизм, с помощью которого формировались списки рассылки для Zimbra в одной из прошлых заметок.

Данное решение не привязано именно к FreePBX, просто web-сервер, имеющийся в её составе, используется для публикации файла списка контактов, его с тем же успехом можно опубликовать на любом другом web-сервере.

Для удобства создадим ссылку /usr/bin/python3, чтобы не было необходимости вспоминать, какая версия python3 стоит на сервере. По непонятной причине это не сделано во FreePBX Distro изначально.
ln -s /usr/bin/python3.6 /usr/bin/python3
Для того чтобы из python обращаться к Active Directory, нужно установить модуль python-ldap. Для его установки понадобится менеджер пакетов python - pip.
# установка pip
python3 -m ensurepip
# обновление его
pip3 install --upgrade pip
Для установки python-ldap через pip, согласно документации, необходимо предварительно установить openldap-devel и python-devel.
FreePBX Disro основан на CentOS, но если выполнить, согласно инструкции,
yum install python3-devel 
то вывалится куча ошибок конфликтов файлов.
Это происходит из-за того, что во FreePBX Distro используется python3 не из репозитория EPEL, а из репозитория IUS Community Project. Это можно увидеть выполнив команду
yum list installed python36* -q | tr -s ' ' | column -t
Результат выполнения которой будет примерно следующим
Installed                         Packages
python36u.x86_64                  3.6.7-1.ius.centos7   @anaconda/2011
python36u-PyYAML.x86_64           3.12-1.sng7           @anaconda/2011
python36u-aiohttp.x86_64          2.2.4-1.sng7          @anaconda/2011
python36u-aiohttp-swagger.x86_64  1.0.5-1.sng7          @anaconda/2011
python36u-argparse.x86_64         1.4.0-1.sng7          @anaconda/2011
python36u-asn1crypto.x86_64       0.23.0-1.sng7         @anaconda/2011
python36u-async_timeout.noarch    1.2.1-1.sng7          @anaconda/2011
...
Как можно заметить, у всех пакетов после версии python указана буква u, что и говорит об использовании репозитория IUS Community.
Чтобы устновить пакеты без ошибок, необходимо прямо указать, из набора какого репозитория их нужно устанавливать
yum install -y python36u-devel openldap-devel
Когда все предварительные требования соблюдены, можно устновить python-ldap
pip3 insatall pyldap
Теперь непосредственно сам скрипт, который будет формировать необходимый нам xml-файл.
touch /scripts/ldap_phonebook.py
Он будет получать список всех пользователей из определённого OU в Active Directory, у которых указан номер телефона, и из этой выборки формировать список контактов.
#!/usr/bin/python3
# coding=UTF-8
# файл списка контактов
contacts_file = '/var/www/phonebook/contacts.xml'
# корень просмотра Active Directory
scope = 'DC=oldfag,DC=ru'
# фильтр для поиска учётных записей
ldapfilter = '(&(telephoneNumber=*)(objectClass=user))'
# домен Active Directory
domain = 'oldfag.ru'
# порт подключения LDAP
port = '389'
# имя пользователя и пароль для подключения к Active Directory
ldapbind = 'ldap_sync'
ldappassword = 'userpassword'

# -------------------------------
# ниже ничего менять не нужно
# -------------------------------

import ldap
from xml.dom import minidom
import xml.etree.cElementTree as ET

# подключение к Active Directory
ad=ldap.initialize('ldap://'+domain+':'+port)
ad.protocol_version=ldap.VERSION3
ad.set_option(ldap.OPT_REFERRALS, 0)
ad.simple_bind_s(ldapbind+'@'+domain,ldappassword)

# получение списка пользователей
res = []
try:
    res=ad.search_s(scope, ldap.SCOPE_SUBTREE, ldapfilter, ['displayName','telephoneNumber'])
    # формирование корня xml-документа с указанием интервала обновления
    root = ET.Element('contacts', refresh='3600')
    # заполнение списка контактов
    for rec in res:
    	ET.SubElement(root, 'contact', name=rec[1]['displayName'][0].decode('utf-8'), number=rec[1]['telephoneNumber'][0].decode('utf-8'), presence='1')
    # сортировка и запись в файл
    root[:] = sorted(root, key=lambda child: (child.tag,child.get('name')), reverse=True)
    xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml(indent="   ")
    with open(contacts_file, 'wb') as xml_file:
    	xml_file.write(xmlstr.encode('utf-8'))
# обработка ошибок
except ldap.LDAPError as error_message:
    print(error_message)
ad.unbind_s()
Стоит обратить внимение на то, что список контактов изначально формируется отсортированным в обратном порядке, это необходиом, чтобы в MicroSIP он загружался с нормальной сортировкой имён пользователей. Так же стоит обратить внимание на указание интервала обновления. Он указан в секундах и по его истечении MicroSIP попробует обновить хранящийся у пользователя локально список с сервера, указанного в настройках.

Файл списка контактов готов, осталось опубликовать его на apache.
Проверяем, что в конце /etc/httpd/conf/httpd.conf есть строки
# Load config files in the "/etc/httpd/conf.d" directory, if any.
IncludeOptional conf.d/*.conf
и создаём дополнительный файл конфигурации, описывающий директорию /phonebook,
touch /etc/httpd/conf.d/phonebook.conf
со следующим содержимым
Alias /phonebook /var/www/phonebook

<Directory "/var/www/phonebook">
    <IfModule mime_module>
        AddType application/xml .xml
    </IfModule>
    DirectoryIndex contacts.xml
    Require all granted
</Directory>
Перезагружаем apache и проверяем, что по адресу http://freepbx.oldfag.ru/phonebook открывается страница со списком контактов, отформатированным как xml-документ.
systemctl restart httpd
Осталось добавить в /etc/crontab задачу на периодический запуск скрипта
# Update ldap phonebook
00 */1 * * * root /usr/bin/python3 /scripts/ldap_phonebook.py
Список контактов на сервере будет обновляться каждый час (задаётся в параметрах задачи для cron), с этой же периодичностью он будет обновляться и у пользователей (задаётся в xml-файле, который MicroSIP загружает с сервера).

Комментариев нет:

Отправка комментария