Sometimes you need to do strange things – and then PHP is the language of choice if you need a solution for web applications in really special environments like using a Windows based authentication method on a Linux server. Here at Mayflower GmbH / ThinkPHP we wrote a proxy server for the authentication with NTLM (NT LAN Manager). This piece of software is used by one of our costumers for two years now without any bigger problems. It does silently its job for hundreds of users each day and they never know what’s happening in the background.
NTLM is an authentication protocol which is widely used in Microsoft based network environments. By using it with HTTP you can use that method for single-sign-on (SSO) authentication within your web browser. NTLM is supported by Microsoft Internet Explorer and Mozilla based browsers like Firefox or Seamonkey. There’s also a module of the Apache webserver called mod_ntlm which can be used for the authentication in Windows based networks.
How NTLM works
NTLM is a so called challenge-response method between a client (which wants to be authenticated) and a server (which needs an authentication by the client). The handshake is done by three messages, the type 1 (negotiation), the type 2 (challenge) and the type 3 (authentication). Every message begins with the hexadecimal encoded string „NTLMSSP“. The process is working like the following steps:
- The client sends a GET request to the server or proxy, the server answers with a 401 header and calls for a NTLM authentication.
- Now the client sends the type 1 message with the required information (Windows user name, name of the domain, the password hash, the size of the key for the encryption, and the request of the shared authentication) to the server. The server then answers with the type 2 message and a 401 header. Additionally the server also sends the same information and permits the client to authenticate with these parameters. Secluding the server also sends a random hash string to the string.
- In the third message the client uses this random hash string received from the server and the Windows authorization information of the user for the evaluation of the answer. This method is based on MD4/MD5 hasing algorithms and a DES encryption. Now the client sends the answer to the server. The server checks the password against the „Security Account Manager“ (SAM) database of the domain controller. If everything is okay, the client is authenicated.
You can describe the authentication like that:
1: C --> S GET ... 2: C <-- S 401 Unauthorized WWW-Authenticate: NTLM 3: C --> S GET ... Authorization: NTLM <base64-encoded type-1-message> 4: C <-- S 401 Unauthorized WWW-Authenticate: NTLM <base64-encoded type-2-message> 5: C --> S GET ... Authorization: NTLM <base64-encoded type-3-message> 6: C <-- S 200 Ok
If you’re using a Windows 2000 Server or a Windows Server 2003 instead of a Windows NT Server, the Internet Information Server will send also a WWW-Authenticate: Negotiate. Then the method will use the Kerberos authentiction over Active Directory instead of the authentication with a domain controller.
Now a short example with the encoded messages during the NTLM HTTP authentication:
1: C --> S GET /index.html HTTP/1.1 2: C <-- S HTTP/1.1 401 Unauthorized WWW-Authenticate: NTLM Connection: close 3: C --> S GET /index.html HTTP/1.1 Authorization: NTLM TlRMTVNTUAABAAAABzIAAAYABgArAAAACwALACAAAABXT1JLU1RBVElPTkRPTUFJTg== 4: C <-- S HTTP/1.1 401 Unauthorized WWW-Authenticate: NTLM TlRMTVNTUAACAAAADAAMADAAAAABAoEAASNFZ4mrze8AAAAAAAAAAGIAYgA8AAAARA BPAE0AQQBJAE4AAgAMAEQATwBNAEEASQBOAAEADABTAEUAUgBWAEUAUgAEABQAZAB vAG0AYQBpAG4ALgBjAG8AbQADACIAcwBlAHIAdgBlAHIALgBkAG8AbQBhAGkAbgAuAGMAb wBtAAAAAAA= 5: C --> S GET /index.html HTTP/1.1 Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGoAAAAYABgAggAAAAwADABAAAAACAAIAEwAAAAWABYAV AAAAAAAAACaAAAAAQIAAEQATwBNAEEASQBOAHUAcwBlAHIAVwBPAFIASwBTAFQAQQB UAEkATwBOAMM3zVy9RPyXgqZnr21CfG3mfCDC0+d8ViWpjBwx6BhHRmspst9GgPOZWPuM ITqcxg== 6: C <-- S HTTP/1.1 200 OK
How we implemented it
One of the problems during the implementation was a little browser comunication detail. If the web application sends multiple requests to the server and then the connection breaks after the next requests, the browser needs feedback from the server before getting a new 401 header. If no feedback is send back, the browser closes the authenticated connection to the server.
To avoid this problem the NTLMProxy script sends a simple XHTML page to the browser which will be reloaded for every new server request. In the meantime the $_GET, $_POST, $_REQUEST and $_SERVER variables have to be saved and have to make available for the browser after the reload. So the NTLMProxy administrates the connections to the server and the client at the same time.
During the NTLM handshake the proxy sends multiple 401 headers (Access denied) to the browser and the page will be reloaded. During the requests the proxy have to change his state and have to recognize which steps in the handshake must be done next. Because of that the NTLMProxy have to registered in the PHP session. The successful termination of the handshake can be discovered when the proxy delivers a string.
The initialization of the NTLMProxy is very simple because we only need a valid session:
session_start(); if (!isset($_SESSION['proxy'])) { $_SESSION['proxy'] = new NTLMProxy(); } $_SESSION['proxy']->handleHandshake();
You can get the secret content with just a few lines of code:
$content = $_SESSION['proxy']->get('192.168.0.1', 'www.example.com', '/'); if (is_string($content)) { print htmlspecialchars($content); } elseif (false === $content) { die("Error!"); }
But how we’re using this in the real life? We’re using the NTLMProxy since two years now at a customer where it requests secret informations from a NTLM secured XML interface. Currently several hundreds users with various permissions can access to several millions of datasets with this appalication. It have to be guaranteed that only an authorized user can read and write data for which he has enough rights. The problem is that the PHP web application is running on a LAMP server and the secret data is provided from an IIS webserver.
Problems
There are some minor problems that we recognized in the production. The Internet Explorer 6 on WindowsXP with Service Pack 1 sporadically breaks the connection and the authentication fails. This problem is solved with SP2, but we also found a funny workaround. If the 401 header is bigger than 1460 bytes the issue is solved with SP1. 1460 bytes is the size of one TCP/IP package….
You also need a domain controller which can handle more traffic than a certain DC because the NTLMProxy needs for every request a new authentication from the domain controller. Normally a single user needs the authentication from the domain controller only at the morning beginning with work.
PEARified
I rewrote the whole class the last months and submitted it to PEAR. The package was accepted last week and now I’m preparing the first release of it. The PEAR::NTLMProxy package also uses the PEAR error handling and the PEAR::Log package for logging all stages to the console.
Schreibe einen Kommentar