简体   繁体   English

NTLM身份验证 - 使用PHP获取Windows登录,域和主机

[英]NTLM Authentication - Get Windows login, domain and host in PHP

I am working on a Single Sign-On (SSO) PHP application. 我正在开发一个单点登录(SSO)PHP应用程序。
Users log in their Windows session, and they want to be automatically logged in the application with their Windows account (connected with LDAP Active Directory). 用户登录他们的Windows会话,他们希望使用他们的Windows帐户(与LDAP Active Directory连接)自动登录应用程序。

I tried this 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!";
            }
        }
    }
}
?>

This script is working on this configuration : 此脚本正在处理此配置:

  • Windows server 2003 Windows server 2003
  • Apache 2.2 with module mod_auth_sspi Apache 2.2,模块为mod_auth_sspi

But now I need to implement this on this configuration and it does not work : 但是现在我需要在这个配置上实现它,它不起作用:

  • Windows server 2008 Windows服务器2008
  • Apache 2.4.6 with module mod_authnz_sspi Apache 2.4.6,模块为mod_authnz_sspi

I keep getting "NTLM Flag error!", because of this condition : 我一直收到“NTLM Flag错误!”,因为这个条件:

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

I tried : 我试过了 :

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

because ord($chained64[13]) returns 130, but I can not go in this condition : 因为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!";
    }
}

Because ord($chained64{8}) always returns 1. 因为ord($chained64{8})总是返回1。


Edit 2015-05-11 : 编辑2015-05-11:

  • I tried executing the 'whoami' command in php, like this : echo exec('whoami'); 我尝试在php中执行'whoami'命令,如下所示: echo exec('whoami'); -> when I execute this command in cmd.exe, I get the current logged user, but when I execute it in PHP, I get nt_authority/system. - >当我在cmd.exe中执行此命令时,我得到当前登录的用户,但是当我在PHP中执行它时,我得到了nt_authority / system。

  • I supposed that when PHP executes the 'whoami' command, Windows checks the login of Apache service. 我认为当PHP执行'whoami'命令时,Windows会检查Apache服务的登录。 I went into Apache properties, in the 'Log On' tab, to log on as a valid user of the Active Directory. 我在“登录”选项卡中进入Apache属性,以作为Active Directory的有效用户登录。 But then, when PHP executes echo exec('whoami'); 但是,当PHP执行echo exec('whoami'); , I only get the login used for Apache, and not the current user. ,我只获得用于Apache的登录,而不是当前用户。

  • I am using Internet Explorer 8 to execute the PHP script. 我正在使用Internet Explorer 8来执行PHP脚本。

  • I have this in my Apache httpd.conf ( _PATH_ is the path to my php files, maybe this is wrong ?) : 我在我的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>


Edit 2015-05-12 : 编辑2015-05-12:

  • I am logged as a domain user on the machine 我在计算机上以域用户身份登录

  • When I try with Firefox, I get a prompt for a login and a password. 当我尝试使用Firefox时,我会收到登录和密码的提示。 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. 当我发布提示时,脚本从提示符获取登录,但这不是我想要做的:我必须让它与IE一起工作,我不想再次输入登录名和密码。 I want the login of the current Windows session. 我想要登录当前的Windows会话。

  • In Firefox, I went into about:config to set network.automatic-ntlm-auth.trusted-uris to my domain, thanks to @ThaDafinser. 在Firefox中,我进入about:config将network.automatic-ntlm-auth.trusted-uris设置为我的域,感谢@ThaDafinser。 Now I do not get a prompt anymore in Firefox and everything works, but I always need to make it work on IE. 现在我在Firefox中没有得到提示,一切正常,但我总是需要让它在IE上工作。

  • In IE, I set Local Intranet Security to the lowest, but nothing changed. 在IE中,我将Local Intranet Security设置为最低,但没有任何改变。

  • In IE, "Automatic logon with current user name and password" is checked for Local Intranet & Trusted Sites. 在IE中,“本地Intranet和可信站点”将检查“使用当前用户名和密码自动登录”。

  • When I force IE to ask credentials in a prompt, if I post the prompt, IE does not return the credentials, contrary to Firefox. 当我强制IE在提示中询问凭据时,如果我发布提示,则IE不会返回凭据,这与Firefox相反。


Edit 2015-05-13 : 编辑2015-05-13:

  • I added the URL to trusted sites in IE, nothing changed. 我在IE中将URL添加到可信站点,没有任何改变。

  • I set security to low for trusted sites, nothing changed. 我将可信站点的安全性设置为低,没有任何改变。

  • I unchecked "Use HTTP 1.1 through proxy connections" in IE > Internet Options > Advanced, I still can not have session informations on Internet Explorer, even if I use the prompt. 我在IE> Internet选项>高级中取消选中“使用HTTP 1.1通过代理连接”,即使我使用提示,我仍然无法在Internet Explorer上拥有会话信息。

  • I added the full URL in Internet Explorer > Internet Options > Security > Local Intranet > Sites > Advanced 我在Internet Explorer> Internet选项>安全性>本地Intranet>站点>高级中添加了完整URL

  • In Internet Explorer > Internet Options > Security > Local Intranet > Sites > Advanced, I also added the same part of the domain (mycompany.com) than I have added in Firefox to make it work, but this did not help. 在Internet Explorer> Internet选项>安全性>本地Intranet>站点>高级,我还添加了与我在Firefox中添加的域相同的部分(mycompany.com),以使其工作,但这没有帮助。

Edit 2015-05-18 : 编辑2015-05-18:

Changed my httpd.conf to be compatible with Apache 2.4, according to what @timclutton said in his answer : 根据@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>

Edit 2015-05-19 : 编辑2015-05-19:

  • I tried to set a basic authentication intead of SSPI and it does not work. 我试图设置SSPI的基本身份验证内容,但它不起作用。

    AuthType Basic AuthName "Authentication Required" AuthUserFile "E:/ PATH /.htpasswd" Require valid-user AuthType Basic AuthName“需要验证”AuthUserFile“E:/ PATH /.htpasswd”需要有效用户

    Order allow,deny Allow from all 订单允许,拒绝允许所有人

When I try with Firefox, I get a prompt for a login and a password. 当我尝试使用Firefox时,我会收到登录和密码的提示。 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. 当我发布提示时,脚本从提示符获取登录,但这不是我想要做的:我必须让它与IE一起工作,我不想再次输入登录名和密码。 I want the login of the current Windows session. 我想要登录当前的Windows会话。

You can remove the prompt, by changing the Firefox settings: 您可以通过更改Firefox设置来删除提示:

  • Type: "about:config" in the addressbar 在地址栏中输入:“about:config”
  • Check for network.automatic-ntlm-auth.trusted-uris 检查network.automatic-ntlm-auth.trusted-uris
  • Set the value to your domain, or part of the domain eg mycompany.com (seperate with comma multiple values) 将值设置为您的域,或域的一部分,例如mycompany.com(用逗号分隔多个值)

For IE you need to set the security settings for your page (intranet) lower than for the rest of the internet. 对于IE,您需要将页面(Intranet)的安全设置设置为低于Internet的其余部分。 Please see https://superuser.com/questions/148063/why-does-internet-explorer-keep-asking-me-for-ntlm-credentials-in-an-intranet-zo 请参阅https://superuser.com/questions/148063/why-does-internet-explorer-keep-asking-me-for-ntlm-credentials-in-an-intranet-zo

The mod_authnz_sspi module handles all aspects of the authentication process transparently, meaning that there is no need for your PHP authentication script. mod_authnz_sspi模块透明地处理身份验证过程的所有方面,这意味着您不需要PHP身份验证脚本。 If the module is configured correctly you should simply be able to reference $_SERVER['REMOTE_USER'] in your script. 如果模块配置正确,您应该只需在脚本中引用$_SERVER['REMOTE_USER'] Any user that cannot be authenticated will receive a standard Apache 403 - Forbidden error. 任何无法通过身份验证的用户都将收到标准的Apache 403 - Forbidden错误。

I suspect the problem is with your httpd.conf since you are using the Apache 2.2 allow/deny syntax and this won't work in Apache 2.4 (unless you have the mod_access_compat module enabled). 我怀疑问题出在你的httpd.conf因为你使用的是Apache 2.2 allow/deny语法,这在Apache 2.4中不起作用(除非你启用了mod_access_compat模块)。 You should read Upgrading to 2.4 from 2.2 in the Apache documentation. 您应该阅读Apache文档中从2.2升级到2.4

Ensure that E:/_PATH_ is the exact folder from which your PHP script is running and every request to that path will require authentication. 确保E:/_PATH_是运行PHP脚本的确切文件夹,并且对该路径的每个请求都需要进行身份验证。

The following works for me on Apache 2.4: 以下适用于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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM