LDAPНаша школа подключена к GSuite Education и все сотрудники имеют электронную почту по фамилии и на нашем домене.
У
гугля есть инструкция, которая, хоть и понятная, но тоже всё не сразу пошло.
До
4 пункта части подключения, проблем нет вообще. Всё делается именно так, как описано.
Теперь мы тут:
4. Подключение LDAP-клиентов к сервису Secure LDAPRunaWFE==Java, так что
переходим сразу в соответствующий разделКонвертируем сертификат первой командой. На второй команде засада, ибо альт не знает команду keytool.
Поэтому
# find / -name keytool
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.212.b04-0.x86_64/jre/bin/keytool
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.212.b04-0.x86_64/bin/keytool
И команда выполняется так:
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.212.b04-0.x86_64/jre/bin/keytool -v -importkeystore -srckeystore java-application-ldap.pkcs12 -srcstoretype PKCS12 -destkeystore java-application-ldap.jks -deststoretype JKS
Чтобы заработало
тестирование соединения с помощью ldapsearch необходимо
настроить OpenLDAP по инструкции, используя в качестве сертификатов полученные с гугла, иначе будет ругань на самоподписанность.
Эту проверку и надо подавить, иначе ничего протестировать нормально не получится.
Открываем
документацию по LDAP на сайте Руны и приступаем к конфигурированию.
Итоговый файл настройки дополнительных возможностей
wfe.custom.system.context.xml,
куда я и рассылку добавлял, у меня выглядит так:
$ cat wfe.custom.system.context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<bean class="ru.runa.wfe.task.EmailTaskNotifier">
<property name="configLocation" value="email.config.xml" />
<property name="onlyIfTaskActorEmailDefined" value="true" />
</bean>
<bean id="loginModuleConfiguration" class="ru.runa.wfe.security.auth.LoginModuleConfiguration">
<property name="loginModuleClassNames">
<list>
<value>ru.runa.wfe.security.auth.LdapLoginModule</value>
<value>ru.runa.wfe.security.auth.InternalDBPasswordLoginModule</value>
</list>
</property>
</bean>
</beans>
Переходим к
конфигурированию файла самого LDAP по разделу инструкции.
Вспоминая
про прикол с database.properties файл я назвал
wfe.custom.ldap.properties. Размещено всё в директории
/opt/runawfe/standalone/wfe.customНабор атрибутов
смотрим в инструкции гугла.
cat wfe.custom.ldap.properties
################################
# Common connection settings
################################
# allowed http://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-ldap.html
java.naming.factory.initial = com.sun.jndi.ldap.LdapCtxFactory
java.naming.provider.url = ldaps://ldap.google.com/
java.naming.security.authentication = none
java.naming.ldap.version = 3
################################
# Authentication module settings
################################
# How to map the user id entered by the user to that passed through to LDAP
# Supported placeholders are: ${username} (user login)
# Examples
# AD (default) DOMAIN\\${username}
# AD UPN ${username}@domain
# AD DN cn=${username},ou=xyz,dc=domain
# OpenLDAP simple uid=${username},ou=People,dc=domain,dc=com
# OpenLDAP DIGEST-MD5 ${username}
authentication.username.format = ${username}@school830.ru
################################
# Synchronization module settings
################################
synchronization.enabled = true
synchronization.import.group.name = ldap users
synchronization.import.group.description = users imported from ldap server
synchronization.waste.group.name = ldap waste
synchronization.waste.group.description = users and groups deleted from ldap server
java.naming.referral = follow
# authorized subject to read directory
java.naming.security.principal = dc=school830,dc=ru
#java.naming.security.credentials = secret
# organization units you want to import separated by <;>
synchronization.organization.units = ou=Users,dc=school830,dc=ru
# partial synchronization can be enabled
synchronization.create.executors.enabled = true
synchronization.update.executors.enabled = true
synchronization.delete.executors.enabled = true
synchronization.user.status.enabled = true
# types
synchronization.object.class.filter = (objectclass={0})
synchronization.user.object.class = person
synchronization.group.object.class = groupOfNames
# whether to reset empty attributes
synchronization.empty.attribute.enabled = true
# synchronization attribute mappings
synchronization.account.name.attribute = uid
synchronization.user.fullName.attribute = displayName
#synchronization.user.description.attribute = employeeType
#synchronization.user.title.attribute = title
synchronization.user.email.attribute = mail
#synchronization.user.phone.attribute = telephoneNumber
#synchronization.user.department.attribute = departmentNumber
synchronization.group.description.attribute = displayName
synchronization.group.member.attribute = member
Что нужно сказать.1) ************Бесполезно добавлять сюда, как
сказано в инструкции гугла строки:
javax.net.ssl.keyStore = /<path-to>/java-application-ldap.jks
javax.net.ssl.keyStorePassword = <выбранный выше пароль>
Они, похоже, просто игнорируются. Долго я до этого доходил

Правильно будет
добавить их в сам скрипт запуска.
2) ************Всё будет по сертификату, поэтому надо всё что можно с аудентификацией поотключать:
java.naming.security.authentication = none
java.naming.security.principal = dc=school830,dc=ru
#java.naming.security.credentials = secret
3) ************Возможно, я не понял, как надо правильно это настраивать

synchronization.user.object.class = person
synchronization.group.object.class = groupOfNames
В
наборе атрибутов сказано:
Пользователь
Пользователь в домене. Пользователи отображаются в подразделениях, к которым они отнесены.
objectClass: top, person, organizationalPerson, inetOrgPerson, posixAccount.
Группа
objectClass: top, groupOfNames, posixGroup.
Логика вроде ясна, но мои пробы это настроить, чтобы синхронизировались группы никак не сработали. Подробнее ниже в пятом пункте.
4) ************Строчки
#synchronization.user.description.attribute = employeeType
#synchronization.user.title.attribute = title
#synchronization.user.phone.attribute = telephoneNumber
#synchronization.user.department.attribute = departmentNumber
Закомментированы потому, что если на сервере LDAP такого поля у какого-то юзверя нет, то синхронизация обрывается с ошибкой. Это явно проблема RunaWFE для багзиллы. Очено неудобно
5) ************Строка
synchronization.organization.units = ou=Users,dc=school830,dc=ru
Выглядит именно так, а не так
synchronization.organization.units = ou=Users,dc=school830,dc=ru;ou=Groups,dc=school830,dc=ru
Потому что Руна обрывает синхронизацию с ошибкой "Нул поинтер на name". Полагаю, что тут отсылка к проблеме из 4 пункта. И, возможно, 3 пункта
по этой настройке из кода.
Тут он явно этот name не получил, т.к. у группы этого атрибута просто нет:
String name = getStringAttribute(searchResult, ATTR_ACCOUNT_NAME);
Кажется, всё портит
эта строка, где должно быть, видимо, так:
group = new Group(description, description);
group.setLdapGroupName(description);
или типа того, но я понимаю, что имелось ввиду. Предполагалось, что в
uid будет имя группы, однако
гугл говорит, что это не так:
ldapsearch -H ldaps://ldap.google.com -b "ou=Groups,dc=school830,dc=ru" '(cn=it)'
SASL/EXTERNAL authentication started
SASL username: st=California,c=US,ou=GSuite,cn=LDAP Client,l=Mountain View,o=Google Inc.
SASL SSF: 0
# extended LDIF
#
# LDAPv3
# base <ou=Groups,dc=school830,dc=ru> with scope subtree
# filter: (cn=it)
# requesting: ALL
#
# it, Groups, school830.ru
dn: cn=it,ou=Groups,dc=school830,dc=ru
objectClass: top
objectClass: groupOfNames
objectClass: posixGroup
cn: it
displayName: IT
description:
gidNumber: 1682464537
member: uid=proskurnev.as,ou=Users,dc=school830,dc=ru
member: uid=zorin.ng,ou=Users,dc=school830,dc=ru
memberUid: proskurnev.as
memberUid: zorin.ng
googleAdminCreated: TRUE
# search result
search: 3
result: 0 Success
# numResponses: 2
# numEntries: 1
У группы вообще нет
uid, т.к. имя группы содержится в
cn. Но мы не можем указать
cn, в качестве
synchronization.account.name.attribute,
т.к. для пользователяcn: так называемое стандартное имя, состоящее из двух значений – имени пользователя и отображаемого имени сотрудника.
Трудно предположить к каким последствиям может привести такое двойное имя пользователя.
Код этого модуля нужно править

Может быть даже добавлять в
wfe.custom.ldap.properties настройки типа
synchronization.group.name.attribute - имя для отображения (например,
Бухгалтерия) и
synchronization.group.id.attribute для cn (соответственно
buh). Отображать и синхронизировать обязательно нормальное название "Бухгалтерия", а не "buh". Думаю, что это самое правильное решение.
01:07:56,108 INFO [ru.runa.wfe.security.logic.LdapLogic] (default task-6) Synchronizing executors
01:08:04,461 ERROR [ru.runa.wfe.security.logic.LdapLogic] (default task-6) : java.lang.NullPointerException: name
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:895)
at ru.runa.wfe.user.Executor.<init>(Executor.java:77)
at ru.runa.wfe.user.Group.<init>(Group.java:59)
at ru.runa.wfe.user.Group.<init>(Group.java:55)
at ru.runa.wfe.security.logic.LdapLogic.synchronizeGroups(LdapLogic.java:275)
at ru.runa.wfe.security.logic.LdapLogic.synchronizeExecutors(LdapLogic.java:99)
at ru.runa.wfe.service.impl.SynchronizationServiceBean.synchronizeExecutorsWithLdap(SynchronizationServiceBean.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
(Полностью приложил в текстовом файле)