title: NTLM Authentication - Get Windows login, domain and host in PHP
body: <p>I am working on a Single Sign-On (SSO) PHP application.<br />
   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). </p>
  
  <p>I tried this script :</p>
  
  <pre><code>&lt;?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!";
              }
          }
      }
  }
  ?&gt;
  </code></pre>
  
  <p>This script is working on this configuration :</p>
  
  <ul>
  <li>Windows server 2003</li>
  <li>Apache 2.2 with module mod_auth_sspi</li>
  </ul>
  
  <p>But now I need to implement this on this configuration and it does not work :</p>
  
  <ul>
  <li>Windows server 2008</li>
  <li>Apache 2.4.6 with module mod_authnz_sspi</li>
  </ul>
  
  <p>I keep getting "NTLM Flag error!", because of this condition :</p>
  
  <pre><code>if (ord($chained64[13]) != 178){
      echo "NTLM Flag error!";
      exit;
  }
  </code></pre>
  
  <p>I tried :</p>
  
  <pre><code>if (ord($chained64[13]) != 130){
  </code></pre>
  
  <p>because ord($chained64[13]) returns 130, but I can not go in this condition :</p>
  
  <pre><code>} 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!";
      }
  }
  </code></pre>
  
  <p>Because <code>ord($chained64{8})</code> always returns 1.</p>
  
  <hr>
  
  <p>Edit 2015-05-11 :</p>
  
  <ul>
  <li><p>I tried executing the 'whoami' command in php, like this : <code>echo exec('whoami');</code> -> 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.</p></li>
  <li><p>I supposed that when PHP executes the 'whoami' command, Windows checks the login of Apache service. I went into Apache properties, in the 'Log On' tab, to log on as a valid user of the Active Directory. But then, when PHP executes <code>echo exec('whoami');</code>, I only get the login used for Apache, and not the current user.</p></li>
  <li><p>I am using Internet Explorer 8 to execute the PHP script.</p></li>
  <li><p>I have this in my Apache httpd.conf (<code>_PATH_</code> is the path to my php files, maybe this is wrong ?) :</p>
  
  <p><code>&lt;Directory "E:/_PATH_"&gt; 
  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 
  &lt;/Directory&gt;</code></p></li>
  </ul>
  
  <hr>
  
  <p>Edit 2015-05-12 :</p>
  
  <ul>
  <li><p>I am logged as a domain user on the machine</p></li>
  <li><p>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.</p></li>
  <li><p>In Firefox, I went into about:config to set network.automatic-ntlm-auth.trusted-uris to my domain, thanks to @ThaDafinser. Now I do not get a prompt anymore in Firefox and everything works, but I always need to make it work on IE.</p></li>
  <li><p>In IE, I set Local Intranet Security to the lowest, but nothing changed.</p></li>
  <li><p>In IE, "Automatic logon with current user name and password" is checked for Local Intranet &amp; Trusted Sites.</p></li>
  <li><p>When I force IE to ask credentials in a prompt, if I post the prompt, IE does not return the credentials, contrary to Firefox.</p></li>
  </ul>
  
  <hr>
  
  <p>Edit 2015-05-13 :</p>
  
  <ul>
  <li><p>I added the URL to trusted sites in IE, nothing changed.</p></li>
  <li><p>I set security to low for trusted sites, nothing changed.</p></li>
  <li><p>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.</p></li>
  <li><p>I added the full URL in Internet Explorer > Internet Options > Security > Local Intranet > Sites > Advanced</p></li>
  <li><p>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.</p></li>
  </ul>
  
  <p>Edit 2015-05-18 :</p>
  
  <p>Changed my httpd.conf to be compatible with Apache 2.4, according to what @timclutton said in his answer :</p>
  
  <pre><code>&lt;Directory "E:/_PATH_"&gt; 
      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 
  &lt;/Directory&gt;
  </code></pre>
  
  <p>Edit 2015-05-19 :</p>
  
  <ul>
  <li><p>I tried to set a basic authentication intead of SSPI and it does not work. </p>
  
  <p>
    AuthType Basic
    AuthName "Authentication Required"
    AuthUserFile "E:/<em>PATH</em>/.htpasswd"
    Require valid-user</p>
  
  <p>Order allow,deny
    Allow from all
  </p></li>
  </ul>