ASP .NET Support Voice Column
Troubleshooting Forms AuthenticationTo customize this column to your needs, we want to invite you to submit your ideas about topics that interest you and issues that you want to see addressed in future Knowledge Base articles and Support Voice columns. You can submit your ideas and feedback using the Ask For It form. There's also a link to the form at the bottom of this column.
Troubleshooting Forms Authentication
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 OverviewWhen 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:
- The client sends an HTTP GET to Default.aspx. No forms authentication cookie is sent.
- The server sends a 302 response (redirect) to Login.aspx.
- The client sends an HTTP POST to Login.aspx. It includes the login information.
- The server sends a 302 response (redirect) to Default.aspx. The forms authentication cookie is included.
- The client sends an HTTP GET to Default.aspx. This includes the forms authentication cookie.
Reasons that a user may be redirected to the login page
The forms authentication cookie is lost
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:
- Open the IIS Microsoft Management Console (MMC).
- Right-click the Web site, and then click
- Click the Web Site tab, and then click Enable Logging.
- Make sure that the log format is W3C Extended Log File Format.
- Click Properties.
- Click the Advanced tab, and then click
- Under Extended Properties, click to select the Cookie(cs(Cookie)) check box and the Referer (cs(Referer)) check box.
Note You can use Log Parser to parse the IIS Logs. To download Log Parser, visit the following Microsoft Web site:
This is the initial login.
|GET||/Default.aspx||302 (Redirect)||No Cookies|
|GET||/Login.aspx||200 (Success)||No Cookies|
|POST||/Login.aspx||302 (Redirect)||No Cookies|
|GET||/SomePage.aspx||302 (Redirect)||No .ASPXAUTH Cookie|
|GET||/SomePage.aspx||302 (Redirect)||No .ASPXAUTH Cookie|
|GET||/Login.aspx||200 (Success)||No .ASPXAUTH Cookie|
|POST||/Login.aspx||302 (Redirect)||No .ASPXAUTH Cookie|
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.
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.
For more information, click the following article number to view the article in the Microsoft Knowledge Base:
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:
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.
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
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 outThe 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.
I'll point out the main areas here:
- Create a class that implements the IHttpModule interface.
public class FormsAuthEvents : IHttpModule
- 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));
- Implement the Application_BeginRequest event.
private void Application_BeginRequest(Object source, EventArgs e)
…code to log the ticket…
- Retrieve the forms authentication cookie, and then decrypt it.
- 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.
- ClientIP: Ties in the requests to a specific client.