Я работаю над PHP-приложением единого входа (SSO).
Пользователи регистрируются в своем сеансе Windows, и они хотят, чтобы они автоматически вошли в приложение со своей учетной записью Windows (связанной с LDAP Active Directory).
Я пробовал этот скрипт:
<?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!"; } } } } ?>
Этот скрипт работает над этой конфигурацией:
Но теперь мне нужно реализовать это в этой конфигурации, и это не работает:
Я продолжаю получать «ошибку флага 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-скрипта.
У меня это в моем 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, я получаю приглашение для входа и пароля. Когда я отправляю приглашение, скрипт получает логин из приглашения, но это не то, что я хочу сделать: мне нужно заставить это работать с 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» Требовать действительного пользователя
Разрешить заказ, запретить доступ ко всем
Когда я пытаюсь с Firefox, я получаю приглашение для входа и пароля. Когда я отправляю приглашение, скрипт получает логин из приглашения, но это не то, что я хочу сделать: мне нужно заставить это работать с IE, и я не хочу вводить снова логин и пароль. Мне нужен вход в текущий сеанс Windows.
Вы можете удалить приглашение, изменив настройки Firefox:
Для IE вам необходимо установить параметры безопасности для своей страницы (интрасети) ниже, чем для остальной части Интернета. См. https://superuser.com/questions/148063/why-does-internet-explorer-keep-asking-me-for-ntlm-credentials-in-an-intranet-zo.
Модуль mod_authnz_sspi
прозрачно обрабатывает все аспекты процесса аутентификации, что означает, что скрипт проверки подлинности PHP не нужен. Если модуль настроен правильно, вы просто должны ссылаться на $_SERVER['REMOTE_USER']
в своем скрипте. Любой пользователь, который не может быть аутентифицирован, получит стандартную ошибку Apache 403 - Forbidden
.
Я подозреваю, что проблема httpd.conf
с вашим httpd.conf
поскольку вы используете синтаксис allow/deny
Apache 2.2, и это не будет работать в Apache 2.4 (если только модуль mod_access_compat
включен). Вы должны прочитать Upgrading to 2.4 from 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>