Kerberos Authentication Issues

We ran into some problems with Kerberos authentication lately and this forced me to unearth the knowledge I once had about Kerberos.

The Issue:
Some Microsoft employees ran into 400 errors when accessing certain Intranet web pages. A 400 error is pretty much a bad request. Kerberos authentication was the cause for this problem.

The Details:
The web sites in question returned a "400 error - request too long" for content protected with IIS Windows Integrated Authentication. It turns out that people who faced this problem had an Authorization header that was larger than 16kB and that HTTP.SYS (the kernel-mode driver underneath IIS) has a request limit of 16kB, i.e. no request can be larger than 16kB by default.

The problem and the fix - increasing the maximum header size and the maximum request size of HTTP.SYS - is described in this KB article. So why would the Kerberos Authorization get larger than 16kB? Turns out that the Kerberos ticket which is encoded in the Authorization header contains all group memberships of the user who wants to authenticate against the web server. The more groups a user is a member of the larger the Authorization header gets. The magic number of group memberships seems to be around 300.

So here are a couple of ways to investigate the problem if you think you run into similar issues:

1) The whoami tool can tell you your group memberships:

whoami /groups 

2) Here is a piece of ASP.NET code that tells you how big the authorization header is and the group memberships of the authenticating user (just save the file as kerb_check.aspx in your wwwroot directory and turn Windows Integrated authentication on and anonymous authentication off):

<%@Language ="C#"%>
<%
int authHeaderSize = 0;
string username = Request.ServerVariables["AUTH_USER"];
if (username == "")
{
Response.Write("<br/>Authentication is not enabled");
}
else
{
authHeaderSize = Request.Headers["Authorization"].Length;
Response.Write("<h2>Size of " +
username +
"'s Authorization header: <br/><b>" +
authHeaderSize +
"</b> bytes. <p/></h2>");
Response.Write("<h2><br/><b>Group Memberships for user " + username + ":</b></h2>");
int count=0;
System.Security.Principal.WindowsIdentity winId =
(System.Security.Principal.WindowsIdentity)HttpContext.Current.User.Identity;
foreach (System.Security.Principal.IdentityReference ir in winId.Groups)
{
try
{
Response.Write("<br/>" +
((System.Security.Principal.NTAccount)ir.Translate
(typeof(System.Security.Principal.NTAccount))).Value);
count++;
}
catch (Exception inner)
{
Response.Write("<br/> --- cannot resolve group ---");
}
}
Response.Write("<br/><br/><b>You are member of " + count + " groups.</b>");
}
%>

Session-based Authentication
Another problem I discovered while looking at the issue: when Kerberos authentication is used IIS7 and IIS 7.5 force the re-authentication of every request. This is unfortunate because it doesn't scale well. Just imagine a single html page with 50 images. If your Kerberos header is 10kB Internet Explorer sends 510kB (51 requests x10kB authorization header) only for authentication purposes.

When NTLM is used on the other hand, session-based authentication is enabled. If session-based authentication is enabled authentication only has to be done per TCP/IP session. This scales much better because Internet Explorer usually creates only 2 to 6 TCP/IP connections to a web server. HTTP requests are then done within these TCP/IP sessions, i.e. the connections are reused to make multiple requests. So if session-based authentication is enabled instead of sending 510kb authentication headers only 20-60kb authentication headers will be sent by IE.

I'm still investigating why session-based authentication is not used for Kerberos - I hope there is a good reason for it :). There is a configuration property in IIS7.x that allows you to switch Kerberos to session-based authentication. It is the AuthPersistNonNTLM property. If you want to turn on server-wide session-based authentication for Kerberos here is your command:


%windir%\system32\inetsrv\appcmd.exe set config -section:windowsAuthentication /authPersistNonNTLM:"True" /commit:apphost
That's it for today.
 
Thomas

1 Comment

Comments have been disabled for this content.