phpproxynginxsingle-sign-onntlmv2

PHP Single Sign On using NTLMv2


I have a nginx web server, using php-fpm for script execution, and I want to get the NTLMv2 credentials of the client browsing the the server. I have a proxy server within my local network to authenticate my users. The question is, how to do I make the nginx server authenticate, or PHP get the credentials of my users using NTLMv2 and pass me back information? I would obviously need to know their username at least to make sure that the client gets the correct credentials within the system.

I'm fine with making a upstream connection to the proxy server when for example I go to /login.php, so long as it passes the information about the client back to the server about the client, for example the user name found in the Type-3 message, I could then save this information within their session and use it from that point on.


I have a Linux server running nginx, PHP and SQLite within a local area network. The computers that are connecting to this server are all Windows based using Windows Login to the network. The login uses NTLMv2 authentication and to get to websites outside of the network via a proxy that all clients must go through to make a connection to the outside web. What I want to do, is use the NTLMv2 authentication information for the login into the LAN web server. Any suggestions on how I could do this?


Solution

  • I think the easiest way to accomplish something like that, is to simulate a NTLMv2 authentication at the nginx server, redirect the requests to the proxy and check the answer. I can't reproduce your setup, so the code below is not tested but it should work or it should give you a bit of help.

    <?php
    $headers = getallheaders() //Equivalent to apache_request_headers() to get the headers of the request.
    
    if(!isset($headers['Authorization'])) //Check Authorization Header
    {
        header('HTTP/1.1 401 Unauthorized'); //Return Unauthorized Http-Header (NTLM protocol)
        header('WWW-Authenticate: NTLM'); //Authenticcation Information (NTLM protocol)
    }
    else
    {
        if(substr($headers['Authorization'],0,4) == 'NTLM') //Check whether Authorization Header is valid
        {
            $message = base64_decode(substr($headers['Authorization'], 5)) //Get NTLM Message from Authrization header
            if(substr($message, 0, 8) == "NTLMSSP\x00") //Check whether NTLM Message is valid
            {
                if($message[8] == "\x01") //Check whether it's type-1-NTLM Message
                {
                    //$message holds the base64 encoded type-1-NTLM message
                    $ch = curl_init(); //Use cURL to connect to web via proxy
                    curl_setopt($ch, CURLOPT_URL, "http://www.google.com");
                    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: '.$headers['Authorization']));
                    curl_setopt($ch, CURLOPT_PROXY, <Your Proxy Adress>);
                    curl_setopt($ch, CURLOPT_PROXYPORT, <Your Proxy Port>);
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                    $result = curl_exec($ch);
                    $info = curl_getinfo($ch);
                    curl_close($ch);
                    $header = substr($result, 0, $info['header_size']);
                    $body = substr($result, $info['header_size'], $info['download_content_length']-$info['header_size']);
                    $c_headers = explode("\r\n", $header);
                    for($i = 0; $i < (count($c_headers) - 2); $i++)
                    {
                        header($c_headers[$i]);
                        if(substr($c_headers[$i], 0, 16) == "WWW-Authenticate")
                        {
                            //Thats your type-2-message header Format: WWW-Authenticate: NTLM <base64-type-2-message>
                        }
                    }
                }
                else if ($message[8] == "\x03") //Check whether it's type-3-NTLM Message
                {
                    $ch = curl_init(); //Use cURL to connect to web via proxy 
                    curl_setopt($ch, CURLOPT_URL, "http://www.google.com");
                    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: '.$headers['Authorization']));
                    curl_setopt($ch, CURLOPT_PROXY, <Your Proxy Adress>);
                    curl_setopt($ch, CURLOPT_PROXYPORT, <Your Proxy Port>);
                    $result = curl_exec($ch);
                    $info = curl_getinfo($ch);
                    curl_close($ch);
                    if($info['CURLINFO_HTTP_CODE'] == 200)
                    {
                        //Authenticated
                        //$msg holds the base64 encoded type-3-NTLM message (which includes username, domain, workstation)
                    }
                }
            }
        }
    }?>
    

    I used this reference of the NTLM protocol: http://davenport.sourceforge.net/ntlm.html

    I hope it will help you. Feel free to comment.