Я работаю над приложением 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" Требовать действительного пользователя
Разрешить заказ, запретить Разрешить от всех