Microsoft KB Archive/323574

= BUG: Authentication Credentials for the Web Request Are Cached =

PSS ID Number: 323574

Article Last Modified on 10/16/2003

-

The information in this article applies to:


 * Microsoft .NET Framework 1.1
 * Microsoft .NET Framework 1.0
 * Microsoft Internet Information Server 5.0
 * Microsoft Internet Information Services version 5.1
 * Microsoft Internet Information Services version 6.0

-



This article was previously published under Q323574



SYMPTOMS
If you have a Web application that is hosted on a security-enhanced Web site, and a request is made to the Web site by using the HttpWebRequest class, the authentication credentials are cached in the server across several HTTP Web requests on one connection. After the initial request is successful, the subsequent requests may succeed without any credentials or with some credentials that are not valid. This problem occurs if the subsequent requests use the same connection as the initial request. Therefore, a middle-tier Microsoft .NET Framework application may not function correctly. For example, this behavior may affect an ASP.NET application that makes HTTP requests to a Web server.



CAUSE
When the remote Internet Information Server (IIS) enables the Keep-Alive property, the HttpWebRequest reuses the connection. By default, the HTTP Web request is authenticated for all the requests on a connection. Because IIS only authenticates the first request on a connection, subsequent requests to the initial request that are not authenticated may run successfully under the authentication credential of the initial request on the same connection.



RESOLUTION
To work around this problem, use the ConnectionGroupName property of the HttpWebRequest class to maintain separate connection groups for authenticated requests to the Web server. The connection group name can be composed of an MD5 hash over the username and over the domain name. To use the ConnectionGroupName property of the HttpWebRequest class, follow these steps:   Disable the Keep-Alive property on the client. Set the KeepAlive property of the request object to false before the GetResponse call is made.

Microsoft Visual C# .NET Code request.KeepAlive = false; Microsoft Visual Basic .NET Code request.KeepAlive = False   Disable the Keep-Alive property on the Web server.

Use the following Adsutil.vbs script to set the AllowKeepAlive property of the IIS to false: Cscript.exe adsutil.vbs SET W3SVC/1/AllowKeepAlive false   Make IIS authenticate all the requests in the same connection. To do this, use the following code to set the AuthPersistSingleRequest property of IIS to true: Cscript.exe adsutil.vbs SET W3SVC/1/AuthPersistSingleRequest true Use the following CScript.exe tool to change the setting of a single application: Cscript.exe adsutil.vbs SET W3SVC/1/VirDir/AuthPersistSingleRequest true 



STATUS
Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.



Steps to Reproduce the Problem
 Start Microsoft Visual Studio .NET.</li> Create a new console application project by using Visual C# .NET or by using Visual Basic .NET.

By default, Class1.cs is created in Visual C# .NET, and Class1.vb is created in Visual Basic .NET.</li>  Replace the existing code in Class1.cs with the following code:

Visual C# .NET Code using System; using System.IO; using System.Net;

class class1 {   static string CallWithAuthority(string url) {       WebRequest wr = WebRequest.Create(url); CredentialCache myCache = new CredentialCache; myCache.Add(new Uri(url), &quot;Basic&quot;, new NetworkCredential(&quot;username&quot;, &quot;password&quot;)); wr.Credentials = myCache; wr.Method = &quot;GET&quot;; WebResponse resp = null; try {           // Send the request, and then receive the response. resp = wr.GetResponse; }       catch (WebException we) {           // Handle the errors appropriately. return we.Message; }       // Receive the response as a string, and then return the response. return &quot;Successful&quot;; }

static string CallWithoutAuthority(string url) {       WebRequest wr = WebRequest.Create(url); wr.Method = &quot;GET&quot;; WebResponse resp = null; try {           // Send the request, and then receive the response. resp = wr.GetResponse; }       catch (WebException we) {           // Handle the errors appropriately. return we.Message; }       return &quot;Successful&quot;; }

static void Main {       // Access a URL without anonymous access permission. string url = &quot;http://server/virtualdir1/default.htm&quot;; Console.WriteLine(CallWithoutAuthority(url)); Console.WriteLine(CallWithAuthority(url)); Console.WriteLine(CallWithoutAuthority(url)); } } Replace the existing code in Class1.vb with the following code:

Visual Basic .NET Code Imports System Imports System.IO Imports System.Net

Class Class1 Shared Function CallWithAuthority(ByVal url As String) As String Dim wr As WebRequest = WebRequest.Create(url) Dim myCache As CredentialCache = New CredentialCache myCache.Add(New Uri(url), &quot;Basic&quot;, New NetworkCredential(&quot;username&quot;, &quot;password&quot;)) wr.Credentials = myCache wr.Method = &quot;GET&quot; Dim resp As WebResponse = Nothing Try ' Send the request, and then receive the response. resp = wr.GetResponse Catch we As WebException ' Handle the errors appropriately. Return we.Message End Try ' Receive the response as a string, and then return the response. Return &quot;Successful&quot; End Function

Shared Function CallWithoutAuthority(ByVal url As String) As String Dim wr As WebRequest = WebRequest.Create(url) wr.Method = &quot;GET&quot; Dim resp As WebResponse = Nothing Try ' Send the request, and then receive the response. resp = wr.GetResponse Catch we As WebException ' Handle the errors appropriately. Return we.Message End Try Return &quot;Successful&quot; End Function

Shared Sub Main ' Access a URL without anonymous access permission. Dim url As String = &quot;http://server/virtualdir1/default.htm&quot; Console.WriteLine(CallWithoutAuthority(url)) Console.WriteLine(CallWithAuthority(url)) Console.WriteLine(CallWithoutAuthority(url)) End Sub End Class Note In the code, you must modify the, the  , and the   so that they are based on your application. </li> On the Build menu, click Build Solution.</li> On the Debug menu, click Start. In the console window, you may receive the following error message:

The remote server returned an error: (401) Unauthorized.

Successful

Successful

However, you may expect to receive the following error message:

The remote server returned an error: (401) Unauthorized.

Successful

The remote server returned an error: (401) Unauthorized.

</li></ol>

<div class="references_section">