Authentification NTLM-obtenir le login de Windows, le domaine et l'hôte en PHP

je travaille sur une seule application PHP de connexion (SSO).

Les utilisateurs se connectent à leur session Windows, et ils veulent être automatiquement connectés à L'application avec leur compte Windows (connecté avec LDAP Active Directory).

j'ai essayé ce 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("","",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("","",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("","",substr($chained64, $offset_host, $lenght_host));


            if ( $login != NULL){
                echo $login;
            } else {
                echo "NT Login empty!";
            }
        }
    }
}
?>

ce script travaille sur cette configuration:

  • Windows server 2003
  • Apache 2.2 avec module mod_auth_sspi

mais maintenant je dois implémenter ceci sur cette configuration et cela ne fonctionne pas:

  • Windows server 2008
  • Apache 2.4.6 avec module mod_authnz_sspi

Je n'arrête pas de recevoir " erreur de drapeau NTLM!"à cause de cette condition :

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

j'ai essayé :

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

parce que ord($chained64[13]) renvoie 130, mais je ne peux pas aller dans cette condition :

} 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("","",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("","",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("","",substr($chained64, $offset_host, $lenght_host));


    if ( $login != NULL){
        echo $login;
    } else {
        echo "NT Login empty!";
    }
}

Parce que ord($chained64{8}) retourne toujours 1.


Modifier 2015-05-11 :

  • j'ai essayé d'exécuter la commande' whoami ' en php, comme ceci:echo exec('whoami'); - > quand j'exécute cette commande dans cmd.exe, j'obtiens l'utilisateur connecté courant, mais quand je l'exécute en PHP, j'obtiens nt_authority/system.

  • j'ai supposé que lorsque PHP exécute la commande whoami, Windows vérifie le login du service Apache. Je suis allé dans les propriétés Apache, dans le ' Log Sur l'onglet pour ouvrir une session en tant qu'utilisateur valide de l'Active Directory. Mais alors, quand PHP exécute echo exec('whoami');, Je n'obtiens que le login utilisé pour Apache, et pas l'utilisateur courant.

  • J'utilise Internet Explorer 8 pour exécuter le script PHP.

  • j'ai ceci dans mon Apache httpd.conf (_PATH_ est-ce que le chemin vers mes fichiers php, peut-être que c'est mal ?):

    <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>


modifier le 2015-05-12 :

  • je suis connecté comme utilisateur de domaine sur la machine

  • quand J'essaie avec Firefox, J'obtiens une invite pour un login et un mot de passe. Quand je poste l'invite, le script obtient le login à partir de l'invite, mais ce n'est pas ce que je veux faire : je dois faire en sorte que cela fonctionne avec IE, et je ne veux pas taper à nouveau login et password. Je veux le login de la session Windows actuelle.

  • dans Firefox, je suis entré dans about: config à l'ensemble du réseau.automatic-ntlm-auth.j'ai fait confiance à mon domaine, grâce à @ThaDafinser. Maintenant Je ne reçois plus D'invite dans Firefox et tout fonctionne, mais j'ai toujours besoin de le faire fonctionner sur IE.

  • dans IE, j'ai placé la sécurité locale de L'Intranet au plus bas, mais rien n'a changé.

  • dans IE," se connecter automatiquement avec le nom d'utilisateur et le mot de passe actuels " est vérifié pour L'Intranet Local et les Sites de confiance.

  • quand je force IE pour demander des informations d'identification dans un prompt, si je poste le prompt, IE ne renvoie pas les informations d'identification, contrairement à Firefox.


Modifier 2015-05-13 :

  • j'ai ajouté L'URL aux sites de confiance dans IE, rien n'a changé.

  • j'ai mis la sécurité à faible pour les sites de confiance, rien n'a changé.

  • j'ai décoché "Utiliser HTTP 1.1 avec une connexion par proxy" dans IE > Options Internet > Avancé, je Je ne peux toujours pas avoir d'informations de session sur Internet Explorer, même si j'utilise l'invite.

  • j'ai ajouté l'URL complète dans Internet Explorer > Options Internet > Sécurité > Intranet Local > Sites > Avancé

  • dans Internet Explorer > Options Internet > Sécurité > Intranet Local > Sites > avancé, j'ai aussi ajouté la même partie du domaine (mycompany.com) que J'ai ajouté dans Firefox pour le faire fonctionner, mais cela n'a pas aider.

Modifier 2015-05-18 :

J'ai changé mon httpd.conf pour être compatible avec Apache 2.4, selon ce que @timclutton a dit dans sa réponse :

<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 AUTHORITYANONYMOUS LOGON" denied 
</Directory>

Modifier 2015-05-19 :

  • j'ai essayé de définir une authentification de base au lieu de SSPI et cela ne fonctionne pas.

    AuthType Basic AuthName " Authentification Requise" AuthUserFile "E:/ PATH/.htpasswd" Exiger valid-user

    ordre autoriser, nier Permettre à tous

15
demandé sur Maxime Mettey 2015-05-06 10:21:19

2 réponses

quand J'essaye avec Firefox, j'obtiens une invite pour un login et un mot de passe. Quand je poste l'invite, le script obtient le login à partir de l'invite, mais ce n'est pas ce que je veux faire : je dois faire en sorte que cela fonctionne avec IE, et je ne veux pas taper à nouveau login et password. Je veux le login de la session Windows actuelle.

Vous pouvez supprimer L'invite, en changeant les paramètres de Firefox:

  • Type: "about:config" dans la addressbar
  • vérifiez le réseau.automatic-ntlm-auth.trusted-uris
  • définissez la valeur à votre domaine, ou à une partie du domaine E. g mycompany.com (seperate with virgule multiple values)

pour IE vous devez définir les paramètres de sécurité pour votre page (intranet) plus bas que pour le reste de l'internet. S'il vous plaît voir https://superuser.com/questions/148063/why-does-internet-explorer-keep-asking-me-for-ntlm-credentials-in-an-intranet-zo

4
répondu ThaDafinser 2017-03-20 10:18:27

mod_authnz_sspi module gère tous les aspects du processus d'authentification de manière transparente, ce qui signifie qu'il n'y a pas besoin de votre script D'authentification PHP. Si le module est configuré correctement, vous devez simplement être en mesure de référence $_SERVER['REMOTE_USER'] dans votre script. Tout utilisateur qui ne peut pas être authentifié recevra un Apache standard 403 - Forbidden erreur.

je soupçonne que le problème est avec votre httpd.conf puisque vous utilisez Apache 2.2 allow/deny syntaxe et cela ne fonctionnera pas dans Apache 2.4 (sauf si vous avez l' mod_access_compat module activé). Vous devriez lire mise à jour de 2.4 à partir de 2.2 dans la documentation Apache.

S'assurer que E:/_PATH_ est le dossier exact à partir duquel votre script PHP est exécuté et chaque requête vers ce chemin nécessitera une authentification.

La suivante fonctionne pour moi sur 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>
2
répondu timclutton 2015-05-15 14:09:17