NTLM Authentication - получение имени, домена и хоста Windows в PHP

Я работаю над приложением Single Sign-On (SSO) PHP.
 Пользователи регистрируются в своем сеансе Windows, и они хотят, чтобы они автоматически вошли в приложение со своей учетной записью Windows (связанной с LDAP Active Directory).

Я пробовал этот script:

<?php
$headers = apache_request_headers();    // Récupération des l'entêtes client

if (@$_SERVER['HTTP_VIA'] != NULL){ // nous verifions si un proxy est utilisé : parceque l'identification par ntlm ne peut pas passer par un proxy
    echo "Proxy bypass!";
} elseif(!isset($headers['Authorization'])) {           //si l'entete autorisation est inexistante
    header( "HTTP/1.0 401 Unauthorized" );          //envoi au client le mode d'identification
    header( "WWW-Authenticate: NTLM" );         //dans notre cas le NTLM
    exit;                           //on quitte

}

if(isset($headers['Authorization']))                //dans le cas d'une authorisation (identification)
{   
    if(substr($headers['Authorization'],0,5) == 'NTLM '){   // on vérifit que le client soit en NTLM

        $chaine=$headers['Authorization'];                  
        $chaine=substr($chaine, 5);             // recuperation du base64-encoded type1 message
        $chained64=base64_decode($chaine);      // decodage base64 dans $chained64

        if(ord($chained64{8}) == 1){                    
        //        |_ byte signifiant l'etape du processus d'identification (etape 3)        

        // verification du drapeau NTLM "0xb2" à l'offset 13 dans le message type-1-message (comp ie 5.5+) :
            if (ord($chained64[13]) != 178){
                echo "NTLM Flag error!";
                exit;
            }

            $retAuth = "NTLMSSP".chr(000).chr(002).chr(000).chr(000).chr(000).chr(000).chr(000).chr(000);
            $retAuth .= chr(000).chr(040).chr(000).chr(000).chr(000).chr(001).chr(130).chr(000).chr(000);
            $retAuth .= chr(000).chr(002).chr(002).chr(002).chr(000).chr(000).chr(000).chr(000).chr(000);
            $retAuth .= chr(000).chr(000).chr(000).chr(000).chr(000).chr(000).chr(000);

            $retAuth64 =base64_encode($retAuth);        // encode en base64
            $retAuth64 = trim($retAuth64);          // enleve les espaces de debut et de fin
            header( "HTTP/1.0 401 Unauthorized" );      // envoi le nouveau header
            header( "WWW-Authenticate: NTLM $retAuth64" );  // avec l'identification supplémentaire
            exit;

        } else if(ord($chained64{8}) == 3) {
        //             |_ byte signifiant l'etape du processus d'identification (etape 5)

            // on recupere le domaine
            $lenght_domain = (ord($chained64[31])*256 + ord($chained64[30])); // longueur du domain
            $offset_domain = (ord($chained64[33])*256 + ord($chained64[32])); // position du domain.    
            $domain = str_replace("\0","",substr($chained64, $offset_domain, $lenght_domain)); // decoupage du du domain

            //le login
            $lenght_login = (ord($chained64[39])*256 + ord($chained64[38])); // longueur du login.
            $offset_login = (ord($chained64[41])*256 + ord($chained64[40])); // position du login.
            $login = str_replace("\0","",substr($chained64, $offset_login, $lenght_login)); // decoupage du login

            $lenght_host = (ord($chained64[47])*256 + ord($chained64[46]));
            $offset_host = (ord($chained64[49])*256 + ord($chained64[48]));
            $host = str_replace("\0","",substr($chained64, $offset_host, $lenght_host));


            if ( $login != NULL){
                echo $login;
            } else {
                echo "NT Login empty!";
            }
        }
    }
}
?>

Этот script работает над этой конфигурацией:

  • Сервер Windows 2003
  • Apache 2.2 с модулем mod_auth_sspi

Но теперь мне нужно реализовать это в этой конфигурации, и он не работает:

  • Сервер Windows 2008
  • Apache 2.4.6 с модулем mod_authnz_sspi

Я продолжаю получать "ошибку флага NTLM!", из-за этого условия:

if (ord($chained64[13]) != 178){
    echo "NTLM Flag error!";
    exit;
}

Я пробовал:

if (ord($chained64[13]) != 130){

потому что ord ($ clained64 [13]) возвращает 130, но я не могу перейти в это условие:

} else if(ord($chained64{8}) == 3) {
    $lenght_domain = (ord($chained64[31])*256 + ord($chained64[30])); // longueur du domain
    $offset_domain = (ord($chained64[33])*256 + ord($chained64[32])); // position du domain. 
    $domain = str_replace("\0","",substr($chained64, $offset_domain, $lenght_domain)); // decoupage du du domain

    //le login
    $lenght_login = (ord($chained64[39])*256 + ord($chained64[38])); // longueur du login.
    $offset_login = (ord($chained64[41])*256 + ord($chained64[40])); // position du login.
    $login = str_replace("\0","",substr($chained64, $offset_login, $lenght_login)); // decoupage du login

    $lenght_host = (ord($chained64[47])*256 + ord($chained64[46]));
    $offset_host = (ord($chained64[49])*256 + ord($chained64[48]));
    $host = str_replace("\0","",substr($chained64, $offset_host, $lenght_host));


    if ( $login != NULL){
        echo $login;
    } else {
        echo "NT Login empty!";
    }
}

Потому что ord($chained64{8}) всегда возвращает 1.


Изменить 2015-05-11:

  • Я попробовал выполнить команду "whoami" в php, например: echo exec('whoami'); → , когда я выполняю эту команду в cmd.exe, я получаю текущего пользователя в журнале, но когда я выполняю его в PHP, Я получаю nt_authority/system.

  • Я предположил, что, когда PHP выполняет команду "whoami", Windows проверяет логин службы Apache. Я вошел в свойства Apache на вкладке "Вход", чтобы войти в систему как действительный пользователь Active Directory. Но тогда, когда PHP выполняет echo exec('whoami');, я получаю только вход для Apache, а не текущий пользователь.

  • Я использую Internet Explorer 8 для выполнения PHP script.

  • У меня это в моем Apache httpd.conf(_PATH_ - это путь к моим php файлам, может быть, это неправильно?):

    <Directory "E:/_PATH_"> Options None AllowOverride All Order allow,deny Allow from all AuthName "SSPI Protected Place" AuthType SSPI SSPIAuth On SSPIAuthoritative On SSPIOfferBasic On SSPIOmitDomain On Require valid-user </Directory>


Изменить 2015-05-12:

  • Я зарегистрирован как пользователь домена на машине

  • Когда я пытаюсь использовать Firefox, я получаю приглашение для входа и пароля. Когда я отправляю приглашение, script получает логин из приглашения, но это не то, что я хочу сделать: мне нужно заставить это работать с IE, и я не хочу вводить снова логин и пароль. Я хочу войти в текущий сеанс Windows.

  • В Firefox я включил: config, чтобы установить network.automatic-ntlm-auth.trusted-uris в мой домен, благодаря @ThaDafinser. Теперь у меня больше нет подсказки в Firefox, и все работает, но мне всегда нужно заставить его работать над IE.

  • В IE я установил значение Local Intranet Security на минимальное значение, но ничего не изменилось.

  • В IE "Автоматический вход с текущим именем пользователя и паролем" отмечен для локальной интрасети и доверенных сайтов.

  • Когда я заставляю IE запрашивать учетные данные в приглашении, если я отправляю приглашение, IE не возвращает учетные данные, в отличие от Firefox.


Изменить 2015-05-13:

  • Я добавил URL-адрес для доверенных сайтов в IE, ничего не изменилось.

  • Я установил уровень безопасности для доверенных сайтов, ничего не изменилось.

  • Я снял флажок "Использовать HTTP 1.1 через прокси-соединения" в IE > Свойства обозревателя > Дополнительно, я все еще не могу иметь информацию о сеансе в Internet Explorer, даже если я использую приглашение.

  • Я добавил полный URL-адрес в Internet Explorer > Свойства обозревателя > Безопасность > Локальная интрасеть > Сайты > Дополнительно

  • В Internet Explorer > Свойства обозревателя > Безопасность > Локальная интрасеть > Сайты > Дополнительно я также добавил ту же часть домена (mycompany.com), что я добавил в Firefox, чтобы она работала, но это не помогите.

Изменить 2015-05-18:

Изменен мой httpd.conf для совместимости с Apache 2.4, в соответствии с тем, что @timclutton сказал в своем ответе:

<Directory "E:/_PATH_"> 
    Require all denied
    AllowOverride     All
    Options None 

    AuthName          "SSPI Authentication"
    AuthType          SSPI
    SSPIAuth          On
    SSPIAuthoritative On
    SSPIOmitDomain    On
    Require           valid-user
    Require           user "NT AUTHORITY\ANONYMOUS LOGON" denied 
</Directory>

Изменить 2015-05-19:

  • Я попытался установить базовую аутентификацию с SSPI, и это не сработает.

    AuthType Basic AuthName "Требуется аутентификация" AuthUserFile "E:/PATH/.htpasswd" Требовать действительного пользователя

    Разрешить заказ, запретить Разрешить от всех

Ответы

Ответ 1

Когда я пытаюсь использовать Firefox, я получаю приглашение для входа и пароля. Когда я отправляю приглашение, script получает логин из приглашения, но это не то, что я хочу сделать: мне нужно заставить это работать с IE, и я не хочу вводить снова логин и пароль. Я хочу войти в текущий сеанс Windows.

Вы можете удалить приглашение, изменив настройки Firefox:

  • Тип: "about: config" в адресной строке
  • Проверить на network.automatic-ntlm-auth.trusted-uris
  • Задайте значение для своего домена или части домена, например mycompany.com(разделите запятыми несколько значений)

Для IE вам необходимо установить параметры безопасности для своей страницы (интрасети) ниже, чем для остальной части Интернета. См. https://superuser.com/questions/148063/why-does-internet-explorer-keep-asking-me-for-ntlm-credentials-in-an-intranet-zo

Ответ 2

Модуль mod_authnz_sspi прозрачно обрабатывает все аспекты процесса аутентификации, что означает, что вам не нужна ваша аутентификация PHP script. Если модуль настроен правильно, вы должны просто указать $_SERVER['REMOTE_USER'] в script. Любой пользователь, который не может быть аутентифицирован, получит стандартную ошибку Apache 403 - Forbidden.

Я подозреваю, что проблема связана с вашим httpd.conf, поскольку вы используете синтаксис Apache 2.2 allow/deny, и это не будет работать в Apache 2.4 (если у вас не включен модуль mod_access_compat). Вы должны прочитать Обновление до версии 2.4 из 2.2 в документации Apache.

Убедитесь, что E:/_PATH_ - это точная папка, из которой работает ваш PHP скрипт, и для каждого запроса этого пути потребуется аутентификация.

Для Apache 2.4 работает следующее:

<Directory "/path/to/webroot">
    AllowOverride     All
    Options           ExecCGI
    # since I run PHP via mod_fcgi; should also work as 'Options none'.

    AuthName          "SSPI Authentication"
    AuthType          SSPI
    SSPIAuth          On
    SSPIAuthoritative On
    SSPIOmitDomain    On
    Require           valid-user
    Require           user "NT AUTHORITY\ANONYMOUS LOGON" denied
</Directory>