Kerberos Authentication with IIS

So you have decided to go with the delegation security model for your application. You have been developing all of the tiers of your application on your single development box where everything worked according to expectations. You have now separated all of the tiers into separate boxes for testing because this is the deployment scenario in production.

You have gone through the checklists in the Troubleshooting Kerberos Delegation article and made sure all the settings are correct. However, your multi-tier application is failing to flow the identity of the end user to the back end. Something is wrong, but where?

Multi-tier applications that use Kerberos Delegation can be difficult to troubleshoot because it takes a single incorrect configuration setting or problem somewhere along the chain to stop the identity flow. The most logical place to start IMHO is the communication between the client and the first middle tier. Before any Kerberos Delegation can occur, the client and first middle tier must be correctly configured for Kerberos Authentication.

A customer had IE as the client and a web application as the first middle-tier. To quickly learn if the client is authenticating via Kerberos, I asked the customer to create a "Negotiate Test" ASP page. The ASP code below is taken from "How To Use Kerberos with the ServerXMLHTTP Component in MSXML".

<HTML>
<HEAD>
<TITLE>Negotiate Test</TITLE>
</HEAD>
<!--
This script is used to detect if the Negotiate method is using NTLM
(windows NT Challenge-Response) or Kerberos as the authentication
method.
-->
<BODY>
<%
Dim AuthMethod
Dim AuthType
Dim AuthLength
Dim AuthOther

' Get the authentication method being used
AuthMethod = Request.ServerVariables("AUTH_TYPE")

' Get the length of the HTTP_Authorization header (to determine Kerberos or NTLM)
AuthLength = Request.ServerVariables ("HTTP_Authorization")

' If some other authentication method (other than Negotiate) gets used, call it "Other"
If LTrim(RTrim(AuthMethod)) <> "Negotiate" Then AuthOtherMethod

' If Negotiate gets used, go straight to the subroutine to handle it
If LTrim(RTrim(AuthMethod)) = "Negotiate" Then AuthNegotiateMethod

Sub AuthOtherMethod()
' Since anonymous authentication will be blank, let's be sure we realize it's enabled to
If LTrim(RTrim(AuthMethod)) = "" Then AuthMethod = "Anonymous"
Response.Write "<table width=500>The user was logged in using the <B>" & AuthMethod & "</B> authentication method."
Response.Write "<P>&#xa0;&#xa0;&#xa0;&#xa0;If you were expecting a different method to be used,"
Response.Write " please check the settings for the resource you are accessing. Remember, selecting"
Response.Write " multiple authentication methods, or allowing anonymous access can result in a "
Response.Write " different method being used.</table>"
End Sub

Sub AuthNegotiateMethod()
' Typically, NTLM will yield a 150 - 300 byte header, while Kerberos is more like 5000 bytes
If LEN(AuthLength) > 1000 Then AuthType = "Kerberos"
If LEN(AuthLength) < 1000 Then AuthType = "NTLM"
Response.Write "<table width=500>The <B>Negotiate</B> method was used!<BR>"

' Tell us the Authentication method used to authenticate the user (and show a warning about the script)
Response.Write "The user was logged on using <B>" & AuthType & "</B>."
Response.Write "<P><font color=#800000><B>Please do not refresh this page</B></font>.<BR>"
Response.Write "&#xa0;&#xa0;&#xa0;&#xa0;If you do use refresh, <B>Kerberos</B> will always show up as <B>NTLM</B>."
Response.Write " This is because the HTTP_Authorization header is being used to determine the authentication method used."
Response.Write " Since the second request is technically unauthenticated, the length is zero. Please open a new browser"
Response.Write " for any subsequent requests.</table>"
End Sub
%>
</BODY>
</HTML>

I asked the customer to situate this ASP page where his web application pages are physically located on his hard drive. If the ASP page is browsed, you can expect to see something like the following if there is Kerberos authentication between the client browser and IIS.

The Negotiate method was used! the user was logged on using Kerberos.

One thing that compounds the difficulty of troubleshooting Kerberos delegation is some form of caching. It is such that you don't know sometimes if a configuration change has fixed the problem. Because a change appears to not have had an impact on the Kerberos delegation problem, you may be tempted to reverse the change and/or move on to check/change something else.

When you are using IE to browse the "Negotiate Test" ASP, be sure to configure IE to check for newer versions of stored pages with every visit to the page. You can do that by using the following steps:

1) On the Tools menu, click Internet Options.
2) From the General tab, click Settings in the Temporary Internet Files panel.
3) In the Settings dialog box, click to select Every visit to the page in the Check for newer versions of stored pages check box.

Another thing to make sure about is that the browser sees the target web server as being in the Local Intranet Zone. This is easy to determine in IE by having a look at the bottom right hand corner of the IE Browser Window when you browse to "Negotiate Test" ASP. It should say "Local Intranet". If it doesn't say "Local Intranet" you can configure the browser to recognize the web server as a member of the Local Intranet Zone by using the steps in "Intranet site is identified as an Internet site when you use an FQDN or an IP address". Also, the Local Intranet zone within Internet Explorer needs to be set to "Automatic logon only in intranet zone". This setting can be changed within Internet Explorer by doing the following: 

1) On the Tools menu, click Internet Options.
2) Click on the Security Tab.
3) Highlight Local Intranet and click on the Custom Level button.
4) Scroll to the bottom of the window and change the setting under the User Authentication, Logon section.

When the customer browsed to the "Negotiate Test" ASP, we quickly determined that NTLM authentication was occurring. The customer has gone through the magic checklists but he did not set up the web server machine. The machine has been used by other developers and administrators for various testing purposes so the settings on the Default Web Site may have been tampered with. We checked the NTAuthenticationProviders setting under the Default Web Site and found the setting to be just "NTLM". By default, the NTAuthenticationProviders key is not defined and IIS uses "Negotiate,NTLM". Having "Negotiate,NTLM" means that it would try Negotiate method first then NTLM second. For Kerberos Authentication, at least "Negotiate" has to be specified for the NTAuthenticationProviders.

Because we did not want to interfere with what the other developers or administrators were doing, we created the NTAuthenticationProviders key under the relevant virtual directory node in the IIS Metabase for the customer's web application. We then assigned this the value of "Negotiate". After this change, the "Negotiate Test" ASP page showed Kerberos authentication. When we tested the actual web application pages after this change, it was evident that the identity of the end user was being flowed to the back end.

You can set NTAuthenticationProviders for a specific virtual directory in the Default Web Site using something like the following command. Have a look also at "How to configure IIS to support both Kerberos and NTLM authentication" for another example and a corresponding output:

cscript adsutil.vbs set w3svc/1/Root/<virtual Directory Name>/NTAuthenticationProviders "Negotiate,NTLM"