Введение

В одной небольшой организации, плотно сидевшей на продуктах майкрософт, для коммуникаций использовался lync (skype), интегрированный с AD. В один момент руководству надоел аська-стайл мессенджер. К тому же вызывало дикое раздражение обмен картинками в lync - захотел передал, захотел не передал, в групповых чатах картинки вообще непонятно где прятались. Решили перейти на современные.

Итак, задача - мессенджер и ВКС, но чтобы запускался как lync с полным именем и аватаром, без запроса логинов и паролей.

Выбор пал на matrix element и jitsi. Не буду описывать нудные критерии выбора, в сети много обзоров.

Все данные о пользователях хранятся в AD, значит авторизация по kerberos, а данные получаем по ldap. Нас интересует конкретно только три параметра - полное имя, почта, аватар.

Вводные данные:

  • сервер - linux debian

  • клиент - matrix element

  • matrix сервер - synapse с авторизацией oidc

  • провайдер авторизации - keycloak

  • ВКС - jitsi

  • web сервер - apache

Сервер предварительно вводим в домен и генерируем keytab файл. Я сделал это двумя командами:

$ net ads join
$ net ads keytab add http/m.example.local@EXAMLE.LOCAL

Не принципиально как это делать, главное, чтобы у нас в системе был файл /etc/krb5.keytab с server principal = http/m.example.local@EXAMPLE.LOCAL.
В тексте ниже опустим описание установок задействованных приложений, в интернете уйма руководств, не будем засорять пространство.

Установка keycloak

Устанавливаем согласно официальной документации, ничего сложного нет.
Создаем в интерфейсе администрирования новый realm с именем synapse. В новом realm создаем клиента с именем synapse, включаем Client authentication и Authorization в ON, остальное по-умолчанию. Запоминаем, что во вкладке Credentials находится ClientSecret, который нам пригодится позже.

Идем в Identity providers, создаем новый с Alias=synapse, Client ID=synapse. Остальное по умолчанию.

Идем в User federation, добавляем LDAP провайдера, в нем стандартные параметры топопривязки ldap - server, bind dn и т.д. Главное включаем kerberos, здесь как раз пригодился Server principal из введения.

Не забываем, что нужна фотография для аватара пользователя, поэтому переключаемся на вкладку Mappers и добавляем mapper с именем picture. Ldap атрибут wWWHomePage содержит ссылку на jpeg фото пользователя. Остальные значения имени и почты там уже присутствуют.

Установка synapse

Устанавливаем согласно официальной документации, тут тоже все без сложностей. В данной ситуации нас интересует только интеграция с keycloak. Параметр client_secret берем из установки keycloak. В ip_range_whitelist добавляем локальные сети, без этого synapse не будет качать фото из picture_template.

ip_range_whitelist:
  - '172.16.0.0/12'
  - '192.168.0.0/16'

oidc_providers:
  - idp_id: keycloak
    idp_name: "EXAMPLE"
    issuer: "https://m.example.local:8443/realms/synapse"
    client_id: "synapse"
    # секрет берем из установки keycloak
    client_secret: "АБРАКАДАБРА"
    scopes: ["openid", "profile"]
    user_mapping_provider:
      config:
        localpart_template: "{{ user.preferred_username }}"
        display_name_template: "{{ user.given_name }}"
        email_template: "{{ user.email }}"
        # именно picture как в mapper установки keycloak 
        picture_template: "{{ user.picture }}"
    backchannel_logout_enabled: false
    allow_existing_users: true

Установка jitsi

Ну все как обычно - официальная документация, сложностей ноль. В качестве web сервера выбираем apache с доменным именем v.example.local.

После установки отключаем опцию prejoin. Нам не надо запрашивать имя пользователя, ведь мы все делаем автоматически.

На будущее в файле /etc/jitsi/meet/${HOSTNAME}-config.js зададим параметр для gravatar. Просто так.

    prejoinConfig: {
         enabled: false,
    },

    gravatar: {
         baseUrl: 'https://va.example.local/avatar/',
    },

Клиент element

Запускаем с параметром --profile на директорию, содержащую файл config.json:

{
    "default_server_config": {
        "m.homeserver": {
            "base_url": "https://m.example.local",
            "server_name": "m.example.local"
        }
    },
    "disable_custom_urls": true,
    "disable_guests": true,
    "disable_login_language_selector": false,
    "disable_3pid_login": true,
    "force_verification": false,
    "default_country_code": "RU",
    "default_federate": false,
    "default_theme": "dark",
    "permalinkPrefix": "https://m.example.local",
    "room_directory": {
        "servers": ["m.example.local"]
    },
    "jitsi": {
        "preferred_domain": "v.example.local"
    }
}

Запускаем.
Выбираем “Продолжить с EXAMPLE”.

Continue.

Виола!
Клиент запустился, подтянул имя пользователя, почту, аватар и при этом ничего не просил вводить руками, просто два клика. Проверяем виджет с групповой видеоконференцией. Тоже все работает как надо. Имя и аватар на месте.

Можно сдавать проект? А вот и нет. Руководство хочет отдельно пользоваться ВКС без запуска виджета в element.

Настройка jitsi

Вернее до-настройка.
После погружения в тему выяснилось, что jitsi у себя не хранит полное имя, почту и аватар. Даже при настройке авторизации через ldap не подтягивает оттуда ничего. Все эти три параметра динамические и задаются в строке url через якори, а якори не передаются на сторону сервера.
Решаю создать еще один виртуальный хост с авторизацией kerberos - va.example.local. Сначала думал добавить модуль mod_gssapi в apache, он возвращает principal имя и по нему задавать фильтр для выборки из ldap полного имени и фото пользователя и потом перенаправлять на v.example.local с якорями. Но потом вспомнил, что у нас же есть уже настроенный keycloak, значит ставим модуль mod-auth-openidc, который сразу отдает все значения в переменные окружения веб сервера. Пишем временный cgi скрипт для вывода переменных. Вот же они все, начинаются на OIDC_CLAIM_*. Бери и пользуйся.

Запускаем виртуальный хост на apache. Идея такая - пользователь заходит на https://va.example.local, модуль mod-auth-openidc его прозрачно авторизует и сразу работает перенаправление на v.example.local с якорями имени и почты. Аватар jitsi скачает с адреса в параметре gravatar.baseUrl, а он у нас уже задан при установке jitsi.

<VirtualHost *:443>
    ServerName va.example.local

    DocumentRoot /var/www/va


    # ...
    # ... стандартные настройки для SSL, логов и т.д.
    # ...

    OIDCProviderMetadataURL https://m.example.local:8443/realms/synapse/.well-known/openid-configuration
    OIDCRedirectURI https://va.example.local/private
    OIDCCryptoPassphrase some_password
    OIDCClientID synapse
    # здесь указываем секрет из установки keycloak, 
    # он такой же как client_secret в synapse
    OIDCClientSecret АБРАКАДАБРА
    OIDCProviderTokenEndpointAuth client_secret_basic
    OIDCRemoteUserClaim email
    OIDCScope "openid email"
    OIDCPassClaimsAs environment none

    <Location />
        AuthType openid-connect
        Require valid-user
    </Location>

    ScriptAlias "/index.cgi" "/var/www/va/index.cgi"
    RewriteEngine on
    RewriteRule ^/([a-zA-Z0-9]+)$ /index.cgi [PT]
</VirtualHost>

Создаем cgi скрипт /var/www/va/index.cgi. Здесь на bash, но можно написать на чем угодно. Хэш для фейкового gravatar-а считаю MD5, потому что jitsi почему-то по нему обращается, хотя везде в руководствах написано SHA256.

#!/bin/bash

# disable filename globbing
set -f

echo "Content-type: text/html; charset=utf-8"
echo


# должны быть права на запись в директорию /var/www/va
[ -d /var/www/va/avatar/photo ] || mkdir -p /var/www/va/avatar/photo


# качаем jpg файл с фото пользователя
/usr/bin/wget -q -nc --timeout=5 --no-proxy --directory-prefix /var/www/va/avatar/photo/ "$OIDC_CLAIM_picture"


# считаем MD5 сумму почтового адреса 
HASHMD5=`echo -n "$OIDC_CLAIM_email" | /usr/bin/md5sum | /usr/bin/awk '{print $1}'`


# создаем ярлык на фото пользователя
[ -f /var/www/va/avatar/$HASHMD5 ] || \
	ln -s /var/www/va/avatar/photo/`basename "$OIDC_CLAIM_picture"` /var/www/va/avatar/$HASHMD5

# перенаправляем клиента на адрес jitsi с параметрами имени и почты
echo "<html lang=\"en-US\">
    <head>
        <meta charset=\"UTF-8\">
        <script type=\"text/javascript\">
            window.location.href = 'https://v.example.local${REQUEST_URI}#userInfo.displayName=\"${OIDC_CLAIM_given_name}\"&userInfo.email=\"${REMOTE_USER}\"'
        </script>
        <title>Page Redirection</title>
    </head>
    <body>
    </body>
</html>"

Заходим браузером на https://va.example.local и сразу оказываемся на https://v.example.local. Видим стартовую страницу jitsi. Создаем конференцию и у нас имя, почта и аватар на месте. Ни одного ручного ввода ввода пользователь не сделал.

Но ведь у нас домен для ВКС v.example.local, а не va.example.local. Пользователь зайдет напрямую на v.example.local и увидит пустую заглушку. Вот бы сделать так, чтобы при входе на v.example.local веб сервер понимал когда на него зашли напрямую, а когда с va.example.local. Для этого есть переменная HTTP_REFERER. Пробуем.
Открываем стандартный конфиг jitsi виртуального хоста веб сервера, перед единственной директивой RewriteRule добавляем четыре строки:

<VirtualHost>
    # ...
    # ... стандартный конфиг для jitsi
    # ...
    RewriteEngine on

    #- начало вставки ----------
    RewriteCond expr "! %{HTTP_REFERER} -strmatch '*://va.example.local*'"
    RewriteCond expr "! %{HTTP_REFERER} -strmatch '*://m.example.local*'"
    RewriteCond expr "! %{HTTP_USER_AGENT} -strmatch '*Element*'"
    RewriteRule ^/([a-zA-Z0-9]+)$ https://va.example.local/$1 [R]
    #- конец вставки ----------

    RewriteRule ^/([a-zA-Z0-9]+)$ /index.html
</VirtualHost>

Проверяем. Заходим браузером на https://v.example.local. Можно после доменного имени сразу указать subdir, в случае jitsi это означает название конференции. В любом случае идет перенаправление на va.example.local и обратно. Это происходит мгновенно, даже не заметно. В итоге пользователь назван и высокохудожественно изображен. При этом как и хотели никакого ручного ввода не было (ну кроме адреса в адресной строке).

Ну и само собой если используются самоподписанные корневые центры сертификации, их сертификаты надо добавить в доверенные на системе:

  1. системное хранилище java - cacerts

  2. скопировать pem файлы в /etc/ssl/certs, потом c_rehash.

Комментарии (0)