Всем привет !
Егор, спасибо Вам большое, очень помогли ) !
В общем то, авторизация работает как и задумывалось, но не без проблем конечно )
В данный момент имею проблему авторизации учетных записей порталов Bitrix и pfsense.
При тестировании выходила ошибка "ldap_search_ext: Bad search filter (-7)".
Если я подключаю портал на порт 389 openldap proxy, минуя 9000 порт с backend Shell, то авторизация проходит нормально
Для работы авторизации на портале Bitrix был дописан файл search.sh и добавлены условия, при которых удаляются лишние символы из поисковой строки, так как в строке filter было замечены лишние символы, которые генерирует портал. С pfsense пока что не удалось решить. На первый взгляд, данные в строке filter указаны корректно.
#!/bin/bash
while [ 1 ]; do
read TAG VALUE
if [ $? -ne 0 ]; then
break
fi
case "$TAG" in
base:)
BASE=$VALUE
;;
filter:)
FILTER=$VALUE
;;
#include other parameters here
esac
done
if [[ "$FILTER " == *"sAMAccountName"* ]]; then
FILTER_NEW=`echo $FILTER | sed 's/(&(?/(/g' | sed 's/user))/user)/g' | sed 's/?//g'`
echo "It's there - sAMAccountName !!!" $FILTER_NEW >> "/home/test/FILTER.txt"
elif [[ "$FILTER " == *"(|(ou=*)(cn=users))"* ]]; then
FILTER_NEW=$FILTER
echo "It's there - (|(ou=*)(cn=users)) !!!" $FILTER_NEW >> "/home/test/FILTER.txt"
else
FILTER_NEW=`echo $FILTER | sed 's/(&(?/(/g' | sed 's/))/)/g' | sed 's/?//g'`
echo "It's NOT there - sAMAccountName !!!" $FILTER_NEW >> "/home/test/FILTER.txt"
fi
# Search
/usr/bin/ldapsearch -x -LLL -H ldap://127.0.0.1 -b dc=example,dc=ru -D "cn=ldap_view,ou=IT отдел,ou=Users,ou=General,dc=example,dc=ru" -w "Secret123" $FILTER_NEW
echo "RESULT"
echo "code: 0"
exit 0
Файл bind.sh почти не трогал, единственное сделал вывод в файл всех переменных, чтобы понимать, что внутри. Переменную $FIRST_QUERY_FILTER заключил в кавычки при задании переменной FIRST_QUERY_RESULT, так как в случае портала Bitrix передаются данные с пробелом. В моем случае учетная запись "cn=Тест Тестов 1" и выполнение скрипта рушится.
#!/bin/bash
while [ 1 ]; do
read TAG VALUE
if [ $? -ne 0 ]; then
break
fi
case "$TAG" in
dn:)
FIRST_QUERY_FILTER=`echo $VALUE | cut -d ',' -f 1`
USER_ACCOUNT_NAME=`echo $FIRST_QUERY_FILTER | cut -d '=' -f 2`
;;
cred:)
CRED=$VALUE
;;
# include other parameters here
esac
done
# START Тест - вывод значения переменных в файл
echo "FIRST_QUERY_FILTER - $FIRST_QUERY_FILTER" | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;print' >> /home/test/2fa.php.txt
echo "USER_ACCOUNT_NAME - $USER_ACCOUNT_NAME" | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;print' >> /home/test/2fa.php.txt
echo "FIRST_QUERY_FILTER_NEW_NEW - $FIRST_QUERY_FILTER_NEW_NEW" | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;print' >> /home/test/2fa.php.txt
# END Тест - вывод значения переменных в файл
# Получение реального DN пользователя с аутентификацией от RootDN
FIRST_QUERY_RESULT=`/usr/bin/ldapsearch -x -LLL -H ldap://127.0.0.1 -b ou=General,dc=example,dc=ru -D "cn=ldap_view,ou=IT отдел,ou=Users,ou=General,dc=example,dc=ru" -w Secret123 "$FIRST_QUERY_FILTER" 1.1`
# START Тест - вывод значения переменных в файл
echo "FIRST_QUERY_RESULT - $FIRST_QUERY_RESULT" | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;print' >> /home/test/2fa.php.txt
# END Тест - вывод значения переменных в файл
if [[ -z $FIRST_QUERY_RESULT ]]; then
echo "RESULT"
echo "code: 49"
echo "info: Unknown user: $USER_ACCOUNT_NAME"
exit 49
fi
# Получение любого атрибута от DN пользователя
USER_DN=`echo $FIRST_QUERY_RESULT | head -n 1 | perl -MMIME::Base64 -wpe 's/^([^:]+):: (.+)$/"$1: " . decode_base64($2)/e'`
USER_DN=${USER_DN:3}
SECOND_QUERY_RESULT=`/usr/bin/ldapsearch -x -LLL -H ldap://127.0.0.1 -b "$USER_DN" -D "$USER_DN" -w $CRED cn`
#SECOND_QUERY_RESULT=`/usr/bin/ldapsearch -x -LLL -H ldap://127.0.0.1 -b ou=General,dc=example,dc=ru -D "$USER_DN" -w $CRED cn`
# START Тест - вывод значения переменных в файл
echo "USER_DN - $USER_DN\n" | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;print' >> /home/test/2fa.php.txt
echo "SECOND_QUERY_RESULT - $SECOND_QUERY_RESULT" | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;print' >> /home/test/2fa.php.txt
# END Тест - вывод значения переменных в файл
if [[ -z $SECOND_QUERY_RESULT ]]; then
echo "RESULT"
echo "code: 49"
echo "info: Wrong password for $USER_ACCOUNT_NAME"
exit 49
fi
VARUSER_DN=`echo $USER_DN | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;print'`
# Второй фактор
SECOND_FACTOR_TEST=`/usr/bin/php /var/www/html/php_ldap_test_2.php "$USER_ACCOUNT_NAME" "$VARUSER_DN"`
# START Тест - вывод значения переменных в файл
echo "SECOND_FACTOR_TEST - $SECOND_FACTOR_TEST" | perl -MMIME::Base64 -MEncode=decode -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode("UTF-8",decode_base64($1))/eg;print' >> /home/test/2fa.php.txt
# END Тест - вывод значения переменных в файл
echo "*****************************************************" >> /home/test/2fa.php.txt
if [[ $SECOND_FACTOR_TEST != "OK" ]]; then
echo "RESULT"
echo "code: 49"
echo "info: Second factor auth failed for $USER_ACCOUNT_NAME"
exit 49
fi
# Успешное завершение
echo "RESULT"
echo "code: 0"
exit 0
Вот в таком виде пока что собран файл php
<?php
header('Content-type: text/html; charset=utf-8');
require("/var/www/html/inc/ldap_functions.php");
$ldap_user = "cn=ldap_view,ou=it отдел,ou=users,ou=general,dc=example,dc=ru";
$user = $argv[1];
$userdn = $argv[2];
$password = 'Secret123';
$ldapuri = 'ldap://192.168.210.254';
$basedn = 'ou=General,dc=example,dc=ru';
//$filter = "sAMAccountName={$user}";
$filter = "cn=".$user;
$group_2fa = 'a-s-2fa_telegram';
$group_2fa_service = 'a-s-2fa_services';
$startTime = time();
$timeout = 61;
file_put_contents("/home/test/var_user.txt", $user, FILE_APPEND | LOCK_EX);
file_put_contents("/home/test/var_filter.txt", $filter, FILE_APPEND | LOCK_EX);
// Подключение к LDAP-серверу
$ad = ldap_connect($ldapuri) or die('Could not connect to LDAP server.');
// Выбор протокола подключения
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3) or die ("Could not set ldap protocol");
//ldap_set_option($ad, LDAP_OPT_REFERRALS, 0);
// Прохождение авторизации в каталоге от сервисной учетной записи
@ldap_bind($ad,$ldap_user,$password) or die('Could not bind to AD.');
// Поиск значение TelegramID у пользователя
$search = ldap_search($ad, $basedn, $filter) or die ("ldap search failed");
// Создание массива с найденными данными
$entr = ldap_get_entries($ad, $search);
// Определение полного пути для пользователя
//$userdn = getDN($ad, $user, $basedn);
file_put_contents("/home/test/var_userdn.txt", $userdn, FILE_APPEND | LOCK_EX);
// Авторизовать сервисные учетные записи без требования второго фактора
if (checkGroupEx($ad, $userdn, getDN($ad, $group_2fa_service, $basedn)))
{
echo "OK";
// Проверка вхождения пользователя в группу проверки второго фактора
} else if (checkGroupEx($ad, $userdn, getDN($ad, $group_2fa, $basedn))) {
if ($entr["count"] > 0) {
$out_array = print_r($entr,true);
file_put_contents("/home/test/var_entr.txt", $out_array, FILE_APPEND | LOCK_EX);
// Задание переменной со значением TelegramID
$user_chat_id = $entr[0]["telegramid"][0];
$FirstName = $entr[0]["givenname"][0];
$LastName = $entr[0]["sn"][0];
//$teluser = "test";
file_put_contents("/home/test/var_FirstName.txt", $FirstName, FILE_APPEND | LOCK_EX);
file_put_contents("/home/test/var_LastName.txt", $LastName, FILE_APPEND | LOCK_EX);
file_put_contents("/home/test/var_user_chat_id.txt", $user_chat_id, FILE_APPEND | LOCK_EX);
if ($user_chat_id != NULL) {
$callback_data_file = "/home/test/{$user_chat_id}.txt";
if (file_exists($callback_data_file)) {unlink($callback_data_file);}
// Отправка сообщения в телеграм чат
exec("/usr/bin/php -f /var/www/html/SendMessage_authbot.php {$FirstName} {$LastName} {$user_chat_id} > /home/test/exec_php.txt 2>&1 &");
while (true) {
// Обработка ответа в чате
$callback_data = file_get_contents($callback_data_file);
if (($callback_data != NULL) or (time() > $startTime + $timeout)) {
break;
}
}
if ($callback_data != "YES") {echo "ERR";} else {echo "OK";}
}
}
} else {echo "ER";}
//unlink("/home/test/{$user_chat_id}.txt");
ldap_unbind($ad);
?>
Позднее, как приведу скрипты в нормальный вид, могу скинуть сюда. Может кому то пригодится.
Конфиг ldap.conf, работает на порту 389. На нем настроен Proxy в MS AD
cat /etc/ldap/ldap.conf
### Schema includes ###########################################################
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/microsoftattributetype.schema
include /etc/ldap/schema/microsoftattributetypestd.schema
#include /etc/ldap/schema/microsoftobjectclass.schema
#include /etc/ldap/schema/additional_attrs.schema
## Module paths ##############################################################
modulepath /usr/lib/ldap
moduleload back_ldap.la
moduleload rwm.la
# Main settings ###############################################################
pidfile /var/run/slapd/slapd.pid
argsfile /var/run/slapd/slapd.args
### Database definition (Proxy to AD) #########################################
database ldap
readonly yes
protocol-version 3
rebind-as-user yes
uri "ldap://ldap.example.ru"
suffix "dc=example,dc=ru"
overlay rwm
rwm-map attribute uid sAMAccountName
rwm-map attribute mail proxyAddresses
rwm-map objectClass posixGroup group
rwm-map objectClass posixAccount person
rwm-map objectClass memberUid member
rebind-as-user yes
#rootDN cn=ldap_view,ou=IT отдел,ou=Users,ou=General,dc=example,dc=ru
#rootPW Secret123
access to attrs=userPassword
by self write
by anonymous auth
by * none
access to *
by self write
by * none
### Logging ###################################################################
loglevel 256
Конфиг ldap_2fa.cong, работает на порту 9000
cat /etc/ldap/ldap_2fa.conf
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/additional_attrs.schema
modulepath /usr/lib/ldap
moduleload back_shell.so
database shell
suffix "dc=example,dc=ru"
bind /etc/ldap/shell/bind.sh
search /etc/ldap/shell/search.sh
Егор, атрибуты написанные Вами внес в файлик /etc/ldap/schema/microsoftattributetype.schema.
Используемые схемы прикрепляю во вложении.
Пока не понял/не дошли руки понять, для чего используется следующее:
rootDN cn=ldap_view,ou=IT отдел,ou=Users,ou=General,dc=example,dc=ru
rootPW Secret123
Егор, возможно ли дописать схемы или правила, чтобы запросы прилетающие на порт :9000 корректно и одинаково обрабатывались в файлике search.sh для всех используемых порталов ?
Следующим сообщением выложу debug сообщения
Спасибо !