Thursday, July 19, 2012

Integrated Authentication in a Windows Development Environment

Here's a dry topic.  Integrated authentication in a windows development environment.

I've spent the better part of a day trying to find a way to do NTLM authentication via an Apache web server running on a Windows server.  The TL:DR is forget it.  Anything NTLM/Apache related is all written for Unix environments, where you have access to Samba and WinBind, or mod_perl and Apache2::AuthenNTLM, or mod_python and PyAuthenNTLM2 (if your python version is old enough).

In the end, I ended up using IIS7.5 (given that I'm using Windows 7 for my development), but it was still a bit of a pain in the ass to set up.

As you may have gleaned, my regular development environment is PHP and Apache2 (specifically PHP 5.3.14 and Apache 2.2.22 at the time of writing).  However, for this, I require IIS7.5 and a few other toys.

Here are the components to grab.  Some are available via the Microsoft Web Platform Installer, and some are available via the same beast, just not searchable within.

Even though I installed PHP 5.3.X for FastCGI via the Installer, I didn't end up using it.  I switched the event handler in IIS to use the same PHP version that I use with Apache, and the same php.ini.  However, it's still good to install the MS version, because it installs other handy things like the PHP Manager for IIS.

With IIS 7.5, the FastCGI module is not installed via the Installer.  It's available as a Windows feature, and can be located via Control Panel > Programs > Programs and Features > Turn Windows features on or off.  From here, you'll want to enable the following :
  • Internet Information Services > World Wide Web Services > 
    • Application Development Features > CGI
    • Security > Windows Authentication
As a basic test for authentication working, here is a sample program, lifted from here:

<?php
if (!isset($_SERVER['REMOTE_USER']) || $_SERVER['REMOTE_USER'] == '') {
    header('HTTP/1.1 401 Unauthorized');
    header('WWW-Authenticate: Negotiate', false);
    header('WWW-Authenticate: NTLM', false);
    exit;
} else {
    echo '<p>Identified as ' . $_SERVER['REMOTE_USER'] . '</p>';
}
echo phpinfo(); 
?>

The general approach is that the web server has anonymous access and windows authentication access enabled, and lets the application set the authentication challenge when it gets to bits that require authentication.

The first bit is enabling the authentication methods.  In IIS, visit Authentication for the Site.  You should see the different types of authentication you have installed which will include Anonymous Authentication and Windows Authentication at the very least.  If you don't, you may need to restart the IIS service, as well as the IIS UI.

Enable Anonymous Authentication.  IIS7.5 now provides a user called IUSR that can be used for anonymous authentication.  Previously, the anonymous user used to specify the machine name, which caused problems during application migration.  If you have a specific user you'd rather authenticate as, then feel free to use that or the Application pool identity.

Note: I'm not very good with IIS, so some of what I'm doing may not be best practice.

Enable Windows Authentication.  In Advanced Settings, I ended up using Accept for Extended Protection and Enabled Kernel-mode authentication.  I'm not sure that actually need Extended Protection, but it's turned on anyway.  In Providers, ensure that it says Negotiate and NTLM, in that order.

Because this is IIS, and it is integrated with Windows, make sure that your anonymous user has read permissions for your application, and write permissions for your log files and cache directories.

Because I'm accessing the application on the same machine that is hosting it, I needed to do a bit of a registry hack, as noted by Method 1 in http://support.microsoft.com/kb/896861.  I actually think Step 1 of Method 1 is a typo, so just start from Step 2.

And that was almost about it.  From then, when visiting the test site, I was able to specify my username as DOMAIN\username and password, and it would authenticate me.  For extra bonus points, I added the site as a Trusted Site to IE, and it didn't even need to prompt me.  Firefox has a property that does a similar thing (network.automatic-ntlm-auth.trusted-uris).  Chrome (at as 20.0) apparently uses whatever IE does in a Windows environment, so once it is in for IE, it's in for Chrome.  Not sure about Unix and Mac users, but Settings > Show advanced settings... > Network > Change proxy settings... might get you closer.  Windows users will then select Security and can set up their trusted sites from there.  Not sure where Firefox is at with supporting Windows Group Policy these days, but I guess that Chrome will use whatever IE uses.

Hopefully, that will get you up and running.

Note: If you are prompted for a password, perhaps because the site is not set up as a trusted site, it would be recommended to host under HTTPS, since the password will be sent as plain text.  As yet, I'm not sure if there are any incompatibilities with HTTPS and NTLM, if the site is trusted.


1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete