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”

Comments (3)

  1. Anonymous says:

    Hi,

    Thanks for this. I’m exactly in this situation. We’ve rummaged through all the help documents and used the test page you provided. And just like you said, the IIS servers returned:

    “The Negotiate method was used!
    The user was logged on using NTLM.”

    The server that works returned Kerberos. But the problem server doesn’t. Setspn is correct, but I’m worried about the app pools.

    You see, on the same IIS server in question, someone is also using a web project that relies on kerberos delegation. They created a user on the domain, let’s call it domainspecialuser and created a new app work pool, called specialpool and associated it using Setspn. Meantime, mine is still using the default app pool that is running under the default “NetworkService” account. We’ve already ran the cscript script. I’m now worried that the app pool is messing things up. Either that or someone messed around in the metafile.

    I’ve also verified that we are not running any proxies and that we are using FQDN.

    If your web application URL is  http://machinea/webappba, and the other party’s web application URL is http://machinea/webappb, provided that http://machinea/webappb is correctly authenticating users via Kerberos, the following are simple options you can take that may resolve the matter:

    1) Run your web application under the same application pool as the third party, or
    2) Create your own application pool and set the identity to domainspecialuser.

    This is because the necessary SPNs are assigned to the domainspecialuser account which include:

    HTTP/machinea
    HTTP/<machinea FQDN>

    Keberos authentication will not work against http://machinea unless the host process is running under the security context of domainspecialuser account.

    If you wish to maintain the application pool identity as Network Service, and require keberos authentication against your web application, arrange for a domain administrator to give the server an alternative different DNS designation. This is such that you may browse your web application with http://specialdnsdesignation/webappa as well as http://machinea/webappa.

    The next step is to add the following SPNs to machinea account:-

    HTTP/specialdnsdesignation
    HTTP/<specialdnsdesignation FQDN>

    Hence, when you run setspn -l machinea the following must be the result:-

    HTTP/specialdnsdesignation
    HTTP/<specialdnsdesignation FQDN>
    HOST/machinea
    HOST/<machinea FQDN>

     

  2. Anonymous says:

    The one where I try to boil Kerb down to three simple rules, and then decide that’s probably impossible without sub-rules and perhaps a nine article series, and then get bored and go home.