ASP .NET Support Voice Column

Troubleshooting Forms Authentication

Welcome to the ASP.NET Support Voice column! My name is Jerry Orman. I have been with Microsoft over 5 years, and have spent most of my time focused on Web-related technologies such as Microsoft FrontPage and the new Microsoft SharePoint technologies. I have spent the last year working with Microsoft ASP.NET as a support engineer. This month in the Support Voice column, I am going to explain how to troubleshoot Forms Authentication in Microsoft ASP.NET.

Troubleshooting Forms Authentication

When you use Forms Authentication in an ASP.NET application, you may find it necessary to troubleshoot a problem that occurs when the user is randomly redirected to the login page. In an ideal world, this problem would occur in a manner that would let you easily attach a debugger and capture the problem. In production environments, however, this is rarely the case. To troubleshoot a random problem like this one, you need to log information related to the problem so that you can narrow down the root cause. In this column, we'll briefly cover the Forms Authentication concept. We'll then look into which scenarios lead to a user being redirected to the login page and how to capture data that is relevant to isolating the problem. We'll also cover how to implement an IHttpModule interface to log the Forms Authentication information.

Forms Authentication Overview

When a user authenticates to a Web site by using Forms Authentication, the server creates a cookie. The value of the cookie is an encrypted forms authentication ticket. The cookie is passed to the server on each request to the application, and the FormsAuthenticationModule class decrypts the cookie value and determines if the user is valid or not. By default, the FormsAuthenticationModule class is added in the Machine.config file. The FormsAuthenticationModule class manages the FormsAuthentication process. The following is an entry from the Machine.config file:

<httpModule>
     …other modules…
     <add name="FormsAuthentication"
         type="System.Web.Security.FormsAuthenticationModule" />
     …other modules…
</httpModule>

The general HTTP traffic for authenticating by using Forms Authentication looks similar to the following:

  1. The client sends an HTTP GET to Default.aspx. No forms authentication cookie is sent.

  2. The server sends a 302 response (redirect) to Login.aspx.

  3. The client sends an HTTP POST to Login.aspx. It includes the login information.

  4. The server sends a 302 response (redirect) to Default.aspx. The forms authentication cookie is included.

  5. The client sends an HTTP GET to Default.aspx. This includes the forms authentication cookie.

For more information about implementing and using forms authentication, visit the following MSDN Web sites:

http://msdn2.microsoft.com/en-us/library/7t6b43z4.aspx

http://msdn2.microsoft.com/en-us/library/system.web.security.formsauthentication(vs.71).aspx

http://msdn2.microsoft.com/en-us/library/system.web.security.formsauthenticationticket(vs.71).aspxFor more information about sharing forms authentication cookies, visit the following ASP.NET Web site:

http://quickstarts.asp.net/QuickStartv20/aspnet/doc/security/formsauth.aspx

Reasons that a user may be redirected to the login page

The forms authentication cookie is lost

Scenario 1

In this scenario, a user logs on to the Web site. At some point, the client sends a request to the server, and the FormsAuthenticationModule class does not receive the cookie. You can determine if a user request does not contain the cookie by enabling cookie logging in Microsoft Internet Information Services (IIS). To do so, follow these steps:

  1. Open the IIS Microsoft Management Console (MMC).

  2. Right-click the Web site, and then clickProperties.

  3. Click the Web Site tab, and then click Enable Logging.

  4. Make sure that the log format is W3C Extended Log File Format.

  5. Click Properties.

  6. Click the Advanced tab, and then clickExtended Properties.

  7. Under Extended Properties, click to select the Cookie(cs(Cookie)) check box and the Referer (cs(Referer)) check box.

After this problem occurs, determine which client had the problem and that client's IP address. Filter the IIS log on that client's IP address, and view the <cookie> column. Note You can use Log Parser to parse the IIS Logs. To download Log Parser, visit the following Microsoft Web site:

http://www.microsoft.com/download/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07 After you have the list of requests from that specific user, search for the requests to the login page. You know they were redirected to this page, and you want to see the requests before the redirection occurred. If you see something similar to the following, the client either did not send the cookie or the cookie was removed on the network between the client and server. This is the initial login.

Method

Page

Response

Cookies

GET

/Default.aspx

302 (Redirect)

No Cookies

GET

/Login.aspx

200 (Success)

No Cookies

POST

/Login.aspx

302 (Redirect)

No Cookies

GET

/Default.aspx

200 (Success)

.ASPXAUTH

GET

/SomePage.aspx

302 (Redirect)

No .ASPXAUTH Cookie

These are other requests, followed by a request to a page on the site without the .ASPXAUTH cookie.

Method

Page

Response

Cookies

GET

/SomePage.aspx

302 (Redirect)

No .ASPXAUTH Cookie

GET

/Login.aspx

200 (Success)

No .ASPXAUTH Cookie

POST

/Login.aspx

302 (Redirect)

No .ASPXAUTH Cookie

GET

/SomePage.aspx

200 (Success)

.ASPXAUTH

Note The first request from that user is not likely to have a forms authentication cookie unless you are creating a persistent cookie. The IIS Log will only show you the cookies that were received in the request. The first request to have the forms authentication cookie will be on the request after a successful login attempt.

Scenario 2

The forms authentication cookie can also be lost when the client's cookie limit is exceeded. In Microsoft Internet Explorer, there is a limit of 20 cookies. After the 20th cookie is created on the client, previous cookies are removed from the client's collection. If the .ASPXAUTH cookie is removed, the user will be redirected to the login page when the next request is processed. You can troubleshoot these two scenarios in the same way. Look at the request just before the redirection to the login page. If the request to this page generates cookies, this will be something to investigate. You can use Fiddler to view the HTTP headers that are sent to the client. After you capture the traffic, double-click a request, and then click Headers to see the Set-Cookie header. If you trace a successful login, you will see the Set-Cookie header in the response of a successful login. To download Fiddler, visit the following Fiddler Web site:

http://www.fiddlertool.com/fiddler/

Scenario 3

After the request leaves the client, there are various layers that can affect the packets that are being sent. To determine if a network device is removing the cookie, you have to capture a network trace on the client and the server, and then look in the body of the request for the cookie. You want to look at the client request to make sure that the cookie was sent, and check the server trace to make sure that the server received the cookie. Client request This is a GET request after the user has been authenticated. The forms authentication ticket information is highlighted in blue. This confirms that the cookie information left the client. When you use a network capture tool, like Netmon, you see the traffic that actually went through the adapter.

47 45 54 20 68 74 74 70-3a 2f 2f 6c 6f 63 61 6c   GET http://local
68 6f 73 74 2f 46 6f 72-6d 73 41 75 74 68 4c 6f   host/FormsAuthLo
67 54 65 73 74 2f 57 65-62 46 6f 72 6d 31 2e 61   gTest/WebForm1.a
73 70 78 20 48 54 54 50-2f 31 2e 31 0d 0a 41 63   spx HTTP/1.1..Ac
63 65 70 74 3a 20 69 6d-61 67 65 2f 67 69 66 2c   cept: image/gif,
…Other headers of the GET request…
63 68 65 0d 0a 43 6f 6f-6b 69 65 3a 20 2e 41 53   che..Cookie: .AS
50 58 41 55 54 48 3d 33-43 45 46 39 42 39 41 30   PXAUTH=3CEF9B9A0
43 33 37 41 44 46 36 33-45 36 42 44 33 37 42 36   C37ADF63E6BD37B6
39 43 44 41 32 35 30 30-30 46 38 30 37 32 38 46   9CDA25000F80728F
35 31 43 39 35 36 36 44-31 34 43 35 34 31 34 35   51C9566D14C54145
38 31 43 39 33 45 32 41-30 31 44 44 43 44 45 46   81C93E2A01DDCDEF
32 34 41 31 37 34 32 39-34 31 30 43 30 39 37 34   24A17429410C0974
42 33 45 43 42 30 36 34-32 32 38 45 33 35 33 39   B3ECB064228E3539
39 41 38 32 32 42 33 42-39 33 36 44 46 30 38 46   9A822B3B936DF08F
42 41 42 44 33 45 31 30-32 44 30 30 32 31 30 43   BABD3E102D00210C
32 45 31 33 39 38 30 37-39 42 32 33 35 32 39 46   2E1398079B23529F
34 46 35 44 37 34 41 3b-20 50 72 6f 66 69 6c 65   4F5D74A; Profile
3d 56 69 73 69 74 6f 72-49 64 3d 62 32 34 65 62   =VisitorId=b24eb

Server-side request When you look at the request that reached the server, you want make sure that the server received the same information that the client sent. If the server did not receive the same information, you need to investigate other devices on the network to determine where the cookie was removed. Note There have also been instances of ISAPI filters removing cookies. If you confirm that the Web server received the cookie, but the cookie is not listed in the IIS logs, check the ISAPI filters. You may have to remove the filters to see if the problem is resolved.

The forms authentication ticket times out

The other common cause for a user to be redirected is if the forms authentication ticket has expired. The forms authentication ticket can time out in two ways. The first scenario occurs if you use absolute expiration. With absolute expiration, the authentication ticket expires when the expiration time expires. For example, you set an expiration of 20 minutes, and a user visits the site at 2:00 PM. The user will be redirected to the login page if the user visits the site after 2:20 PM. If you use sliding expiration, the scenario is a bit more complicated. The cookie and the resulting ticket are updated if the user visits the site after the expiration time is half-expired. For example, you set an expiration of 20 minutes by using sliding expiration. A user visits the site at 2:00 PM, and the user receives a cookie that is set to expire at 2:20 PM. The expiration is only updated if the user visits the site after 2:10 PM. If the user visits the site at 2:09 PM, the ticket is not updated because half of the expiration time has not passed. If the user then waits 12 minutes, visiting the site at 2:21 PM, the ticket will be expired. The user is redirected to the login page. One way to approach this type of issue is to log the forms authentication cookie and ticket information. This way, you can see if the cookie was received by IIS and what the values are. You can do this by writing an HttpModule, and then plugging that module into the request pipeline. You will not have to modify your application's code to get the information you need. The attached sample works in the Microsoft .NET Framework 1.1 and the .NET Framework 2.0 and has comments throughout. The sample includes the following files:

  • FormsAuthEvents.cs: The class that implements IHttpModule and ties into the Application_BeginRequest event.

  • FormsAuthInfo.cs: The class that retrieves the cookie and decrypts the forms authentication ticket. It also checks the application's Web.config file to ensure that forms authentication is enabled.

  • FormsAuthConfig.cs: The class that reads information from the FormsAuthLogger.config file.

  • Log.cs: The file that accepts a stringbuilder and writes the values out to a log file.

  • FormsAuthLogger.config: The XML file that is read by the Log.cs file. This file has to be in the /bin folder with the Built DLL. The file allows you to configure the following:

    • Filter by IP: You can filter the capture of data by client IP. This way, you can log only requests from a client that is known to reproduce the issue. This reduces the size of the log.

    • Capture Type: This specifies where to save the file. The default is the Temporary ASP.NET Files folder, but you can save this anywhere as long as the worker process account has the ability to write to the folder.

Note I'll provide a download link for the code supplied in the FormsAuthLogger.zip file. I'll point out the main areas here:

  1. Create a class that implements the IHttpModule interface.

    public class FormsAuthEvents : IHttpModule 
    {
    …code…
    }
  2. Wire up the event you want to look at. In this sample, we're using the Application_BeginRequest event. This way we can investigate each request and determine if it has the forms authentication cookie and log the FormsAuthenticationTicket if the cookie is there.

    public void Init(HttpApplication application) 
    {
    //Wire up the BeginRequest event
    application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
    }
  3. Implement the Application_BeginRequest event.

    private void Application_BeginRequest(Object source, EventArgs e)
    {
       …code to log the ticket…
    }
    
  4. Retrieve the forms authentication cookie, and then decrypt it.

  5. Log the values. I would recommend logging the following in addition to the forms information. This will help you line up your forms authentication information to the IIS logs, if necessary:

    • Date: Allows you to see when the request came in.

    • RequestType: Shows whether the request is a Get or a Post.

    • URL: Shows the pattern of requests leading up to the problem.

    • Referrer

    • ClientIP: Ties in the requests to a specific client.

Need more help?

Want more options?

Explore subscription benefits, browse training courses, learn how to secure your device, and more.

Communities help you ask and answer questions, give feedback, and hear from experts with rich knowledge.