PHP+Active Directory. Сквозная авторизация и получение информации о пользователе из домена.

12.09.2016

Здесь рассмотрим выполнение сквозной авторизации пользователя в Active Directory C получением параметров пользователя.
Необходимым условием является наличие пользователя в домене, т.е. пользователь не прописанный в домене не пройдет авторизацию.
Прежде всего необходимо установить соединение нашего php-скрипта с доменом.
Подразумевается, что в AD прописан не только пользователь, но и компьютер пользователя.
Часто в описании пользователя отсутсвует привязка к компьютеру, — этот скрипт проверяет сведения о компьтере в домене и вытягивает всю необходимую информацию.
Сделаем это следующим образом:
1. Получаем имя удаленного хоста, при входе пользователя на страницу.

$hostname = gethostbyaddr($_SERVER['REMOTE_ADDR']);
//echo $hostname;

2. Поскольку полученное имя может быть длинее 15 символов (а именно столько позволяет внести NETBIOS-имя), — обрезаем до необходимой длнины, убираем все символы после первой точки (т.к. полученное имя имя будет иметь формат «логин.субдомен.домен») и в переменную «текущий пользователь» берем результат, добавляя к нему спецсимвол «$».

$hostname = substr($hostname, 0, 15);
list($hostname,) = explode('.',$hostname);
$cur_user=$hostname."$";
//echo $cur_user;

3. Устанавливаем соединение с доменом.
Для этого используем пару «логин-пароль» имеющие права считать информацию из AD.

$ds=ldap_connect("ldap-имя.домен");  // Необходимо указать корректный LDAP сервер
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); // версия протокола зависит от настрое домена, в моем случае = 3
if ($ds) {
$r=ldap_bind($ds, "логин@домен" ,"пароль");     //  не анонимная  привязка,
/*  тут выполняем операции по выборке данных из AD (описаны в пунктах 4 и 5)  */
} else {
echo "<h4>Невозможно подключиться к серверу LDAP</h4>";
}

Получение информации из домена разделим на две составляющие: информация о компьютере и информация о пользователе.
4. Извлечение информации о копьютере.
Эту операцию выполнит следующий код:

$sr=ldap_search($ds, "OU=ESRR, DC=esrr, DC=oao, DC=rzd", "samaccountname=".$cur_user); // живой пример
$info = ldap_get_entries($ds, $sr);
//print_r($info); // выведет всю доступную информацию, из которой и извлечем данные
for ($i=0; $i<$info["count"]; $i++) {
$komp2000=iconv('utf-8', 'cp1251',$info[$i]["name"][0]); // имя компьютера в формате windows 2000 (соответсвует NETBIOS-имени)
$dnsname=iconv('utf-8', 'cp1251',$info[$i]["dnshostname"][0]); // DNS-имя компьтера в домене.
}
//echo "Имя компа :  ".$komp2000."";
//echo "Полный DNS компа  :  ".$dnsname."";
list($dnsname,) = explode('.',$dnsname);
//echo "Краткий DNS компа  :  ".$dnsname."";
// В моем случае компьютеры записаны в домене в формате "префикс-имя компа", а пользователи - "префикс-имя пользователя", при  этом имя компа = имя пользователя, поэтому выполняю операцию замены символа.
$userlogin=str_replace('-','_',$dnsname); // получил логин
$pref = explode("_", $userlogin); // получил префикс
$upref = $pref[0];
// echo "pr :  ".$upref.";
//echo "Логин пользователя  :  ".$userlogin.";

5. Извлечение информации о пользователе (в качестве продолжения кода приведенного в п.4)

$sr2=ldap_search($ds, "OU=ESRR, DC=esrr, DC=oao, DC=rzd", "sAMAccountName=".mb_strtolower($userlogin));// живой пример
// тут mb_strtolower - игнорирование регистра символов
$info2 = ldap_get_entries($ds, $sr2);
for ($i=0; $i<$info2["count"]; $i++) {
$fioful=iconv('utf-8', 'cp1251',$info2[$i]["cn"][0]);
$company=iconv('utf-8', 'cp1251',$info2[$i]["company"][0]);
}
//echo "Полное имя пользователя  :  ".$fioful;
//echo "Предприятие пользователя  :  ".$company;

Выше приведенный способ я использовал по причине запрета доменной политикой использования в браузере ActiveX.
Если же ActiveX у вас разрешен — можно использовать другой способ извлечения из AD информации о пользователе посетившем web-страницу, приведенный ниже:

I. Файл index.php

<script type="text/javascript">
var CurentUser = new ActiveXObject('WScript.Network');
var Param = CurentUser.UserName;
document.write("<form name='FormU' method='post' action='auth.php'><input type='hidden' name='user' value='"+Param+"'></form>");
document.FormU.submit();
//отослали на траницу проверки авторизации
</script>

II. Файл auth.php

$cur_user =$_REQUEST["user"];
$login=$cur_user;
$ds=ldap_connect("esrr-dc-02.esrr.oao.rzd");  // Необходимо указать корректный LDAP сервер
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
if ($ds) {
$r=ldap_bind($ds, "логин@esrr.oao.rzd" ,"пароль");     // " не анонимная" привязка,
$sr=ldap_search($ds, "OU=ESRR, DC=esrr, DC=oao, DC=rzd", "sAMAccountName=".mb_strtolower($login));
$info = ldap_get_entries($ds, $sr);
for ($i=0; $i<$info["count"]; $i++) {
$fioful=iconv('utf-8', 'cp1251',$info[$i]["cn"][0]);
$company=iconv('utf-8', 'cp1251',$info[$i]["company"][0]);
$pref = explode("_", $cur_user);
$upref = $pref[0];
$_SESSION['user_fio']=$fioful; // ФИО пользователя
$_SESSION['user_d']=$login;    // доменное имя пользователя
$_SESSION['user_pred']=$company;  // имя предприятия
}
// ЗДЕСЬ ПРОВЕРЯЕМ КАКОЕ-ЛИБО УСЛОВИЕ
if ($stop == "1"){
header ("Location: ./error.php");
}else{
header ("Location: ./idx.php");
}
// echo "Закрытие соединения";
ldap_close($ds);
} else {
echo "<h4>Невозможно подключиться к серверу LDAP</h4>";
}

Комментарии

6 комментариев к записи “PHP+Active Directory. Сквозная авторизация и получение информации о пользователе из домена.”
  1. Wikis are enabled by wiki software, otherwise known as wiki engines.

  2. Алексей:

    Добрый день. Поясните пожалуйста вот эту вашу фразу:»Подразумевается, что в AD прописан не только пользователь, но и компьютер пользователя.»
    В АД в какие то дополнительный полы прописывается связка логин компьютер?
    Если не трудно чирканите мне в почту. А то уже третий день бьюсь над аналогичной задачей но пока никуда не продвинулся.

    • Maks:

      по нормальному должен быть общий признак, но админы ленивы и редко делают такие связки
      копм и юзер в AD заводятся отдельно
      при наличии общего сделать связку в запросе легко

  3. Виталий:

    Данный метод кустарный и не несет никакой безопасности, т.к. клиент может передать серверу произвольный логин и имя компа. Где же тут обмен токенами?

    • Maks:

      » Где же тут обмен токенами»

      зачем?
      1. пользователь не должен иметь прав переименования компа или имени учетки…
      2. имя компа вторично
      3. юзер считывается с машины и сверяется с доменом
      4. имя юзера должно быть = имени в домене.. + см пункт 1
      Этого достаточно чтобы определить присутствие пользователя в домене и считать его параметры, и нет необходимости в токене при соблюдении всех условий

  4. deface:

    Небольшое дополнение к пункту 5:
    Зачастую при вводе в домен, специалисты осуществляющие ввод ПК в AD не заморачиваются с длиной имени и правильностью написания, и получаются обрезанные имена. Чтобы учесть этот момент — следует в 1 первой строке примера произвести изменения.

    "sAMAccountName=".mb_strtolower($userlogin));

    заменить на

    "sAMAccountName=".mb_strtolower($userlogin)."*");

Оставить комментарий к Maks