Введение
В одной небольшой организации, плотно сидевшей на продуктах майкрософт, для коммуникаций использовался 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 и обратно. Это происходит мгновенно, даже не заметно. В итоге пользователь назван и высокохудожественно изображен. При этом как и хотели никакого ручного ввода не было (ну кроме адреса в адресной строке).
Ну и само собой если используются самоподписанные корневые центры сертификации, их сертификаты надо добавить в доверенные на системе:
системное хранилище java - cacerts
скопировать pem файлы в /etc/ssl/certs, потом c_rehash.