NTLM authentication is a Microsoft-developed technology, originally implemented in the company’s IIS web server product. It’s not widely used on the public internet, but it does integrate nicely with things like Active Directory, so it can be quite useful for web applications used on company intranets that require security based on Active Directory credentials. This means that to provide sample code, we’ll need to have a few things in place first. First, we’ll need a test website that we can run locally, running on a server that implements NTLM authentication. Since we’re working in C# in this series, we can create an ASP.NET Core web project to do that.
Second, we’ll also need to host the application using Windows. Even though the ASP.NET Core project can run against .NET Core, and that can run on platforms other than Windows, we’ll need to actually run on Windows to take advantage of NTLM authentication, unless we want to introduce a ton of complexity with Active Directory domains and the like (which we don’t for this post).
Finally, most browsers bypass the use of a proxy when running strictly on localhost. This means that if you’re running things all on the same system, you’ll need to either configure the browser not to do this, or trick it into thinking the site the browser is connecting to isn’t the local machine. The latter is far easier, since it only involves adding a line to the Windows hosts file (located at %WinDir%\System32\drivers\etc\hosts). On my test system, I’ve redirected www.seleniumhq-test.test to 127.0.0.1 by using the hosts file, and the sample code will reflect this.
NTLM authentication is a challenge-response based authentication scheme, and it differs from other HTTP authentication schemes in that it authenticates a connection, not an individual request. This means that the browser and server must support so-called “keep-alive,” or persistent TCP connections between them. It also means that our proxy has to support persistent TCP connections, and must allow us to use that exact connection for making the requests. Fortunately, the proxy we’ve been using so far, BenderProxy, does support this.
The challenge-response mechanism used is complicated. Very complicated. So again, we’ll be using the PassedBall library to parse authentication headers and generate authorization responses. It also requires multiple request/response round trips to perform the authentication handshake. Here’s the implementation code for handling the NTLM authentication challenge for a sample site hosted on our local host machine:
Note carefully that the initial 401 Unauthorized response may contain multiple WWW-Authenticate headers, so one may need to make sure the proper one is being used to interpret the response. Browsers, when faced with this, will usually choose what they perceive to be the “strongest” authentication method. In our case, we need to do that determination for ourselves.
We’ll wrap up this series with one more post, summing everything up.