php - NTLM 身份验证 - 在 PHP 中获取 Windows 登录名、域和主机

标签 php apache login ntlm windows-server

我正在开发单点登录 (SSO) PHP 应用程序。
用户登录他们的 Windows session ,并且他们希望使用他们的 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!";
            }
        }
    }
}
?>

此脚本正在处理此配置:
  • Windows Server 2003
  • Apache 2.2 模块 mod_auth_sspi

  • 但是现在我需要在这个配置上实现它并且它不起作用:
  • Windows Server 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($chained64[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 :
  • 我尝试在 php 中执行“whoami”命令,如下所示: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 session 的登录。
  • 在 Firefox 中,我进入 about:config 将 network.automatic-ntlm-auth.trusted-uris 设置为我的域,感谢 @ThaDafinser。现在我在 Firefox 中不再收到提示并且一切正常,但我总是需要让它在 IE 上工作。
  • 在 IE 中,我将本地内联网安全设置为最低,但没有任何改变。
  • 在 IE 中,为本地 Intranet 和受信任的站点选中“使用当前用户名和密码自动登录”。
  • 当我强制 IE 在提示中询问凭据时,如果我发布提示,IE 不会返回凭据,这与 Firefox 不同。


  • 编辑 2015-05-13 :
  • 我在 IE 中将 URL 添加到受信任的站点,没有任何改变。
  • 我将受信任站点的安全性设置为低,没有任何改变。
  • 我在 IE > Internet 选项 > 高级中取消选中“通过代理连接使用 HTTP 1.1”,即使我使用提示,我仍然无法在 Internet Explorer 上获得 session 信息。
  • 我在 Internet Explorer > Internet 选项 > 安全 > 本地 Intranet > 站点 > 高级
  • 中添加了完整 URL
  • 在 Internet Explorer > Internet 选项 > 安全 > 本地 Intranet > 站点 > 高级中,我还添加了域 (mycompany.com) 的相同部分,与我在 Firefox 中添加的部分相同,但这没有帮助。

  • 编辑 2015-05-18 :

    根据@timclutton 在他的回答中所说,将我的 httpd.conf 更改为与 Apache 2.4 兼容:
    <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 基本
    AuthName "需要身份验证"
    AuthUserFile "E:/PATH/.htpasswd"
    需要有效用户

    命令允许,拒绝
    所有人都允许
  • 最佳答案

    When I try with Firefox, I get a prompt for a login and a password. When I post the prompt, the script gets the login from the prompt, but this is not what I want to do : I have to get this to work with IE, and I don't want to type again login and password. I want the login of the current Windows session.



    您可以通过更改 Firefox 设置来删除提示:
  • 在地址栏中输入:“about:config”
  • 检查 network.automatic-ntlm-auth.trusted-uris
  • 将值设置为您的域,或域的一部分,例如 mycompany.com(用逗号分隔多个值)

  • 对于 IE,您需要将页面(内联网)的安全设置设置为低于 Internet 其余部分的安全设置。
    请查看 https://superuser.com/questions/148063/why-does-internet-explorer-keep-asking-me-for-ntlm-credentials-in-an-intranet-zo

    关于php - NTLM 身份验证 - 在 PHP 中获取 Windows 登录名、域和主机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30070058/

    相关文章:

    php - 新的 APCu APC 用户缓存是否在进程之间共享?

    使用 SourceTree 登录 Git 失败,想改为使用 SSH 创建登录

    php - gzip压缩不适用于xampp

    php - HTTP API 的排序结果

    php - mysql fetch assoc 用于 url 获取

    apache - 我可以为所有 VirtualHost 使用一个 SSLCertificateFile,而不是为每个 VirtualHost 创建一个 SSLCertificateFile 吗?

    apache将单个子域映射到文件夹

    login - 如何为 Web 应用程序实现登录系统?

    匿名用户身份验证

    php - 有人用过 PHP 的(未设置的)转换吗?