I recently had a customer that just moved from Windows 2008 to Windows 2008 R2 (changing from IIS 7 to IIS 7.5) and after the move they got some weird forms authentication errors in the event log
They have two applications (MyWebApp and MyLoginWebApp) where forms authentication is dealt with in MyLoginWebApp
<forms name="MyAppAuth" loginUrl="/MyLoginWebApp/Default.aspx" protection="All" timeout="720" path="/" slidingExpiration="true" />
Once the user is authenticated they are redirected back to MyWebApp but on the redirect, forms authentication fails (and logs events like the below), and redirects back to the MyLoginWebApp application.
Event ID: 1315
Event message: Forms authentication failed for the request
Reason: The ticket supplied was invalid
The two applications are setup to run in different application pools in order to avoid problems occurring in one of the apps to affect the other.
Autogenerated machine keys
Forms authentication requires a machine key to encrypt and decrypt the ticket and this has to be the same on the sending and receiving end. You can use to specify a manually generated key or use an autogenerated one.
Now, by default when using AutoGenerate machinekeys, the autogenerated machinekey is isolated per application.
To be able to use the same autogenerated machinekey over multiple applications you need to go in to IIS Manager (on IIS7+) and in the Machine Key settings, uncheck the box for “Generate a unique key for each application”. If you are running IIS6, you can remove the IsolateApps keyword from the <MachineKey…> tag in Machine.Config to allow for the key to be the same across applications.
If you are crossing applications, and especially if you are in a web farm scenario where you may be crossing machine boundaries, you should consider using a pre-generated Machine Key rather than an autogenerated one.
Using a manually generated key actually worked for them, but for various reasons they wanted to use an AutoGenerated one and as this worked in IIS 7 they were curious why it didn’t work now.
To get to the bottom of the problem I started looking at how these autogenerated keys were stored and what could be causing the two applications to not use the same one.
I found this blog post by Kev talking about exactly that and describing how the autogenkey was stored in the registry. The blog post actually talks about the exact same issue we are seeing. In his case the reason for the failure was that if the process doesn’t have permissions to write to the registry it has to regenerate the key each time a process starts up.
So just for house keeping, the registry key where the autogenerated key is stored is:
This seemed to fit our problem pretty well. When you are separating the apps out into different application pools they run in different processes, and if they didn’t have enough permissions to write the key it would be autogenerated at startup (different ones for the different application pools).
The problem was that I could reproduce this, and I could see the autogen keys in my registry so I knew that we didn’t have trouble writing it.
While looking at this though, I discovered that my two application pools were running under different users (for example the user for the DefaultAppPool was DefaultAppPool and the user for my TestAppPool was TestAppPool).
Looking back at the registry key, it contains a SID, so the autogenkey is stored on a per user bases, i.e. in our case, since the two processes are running under different users they would have different autogen keys, which explains why we are seeing issues here.
It turns out that there was a change between 7 and 7.5 that Dave wrote about here where they changed the default identity of the application pool from Network Service to an automatically generated AppPool identity. So this is why there was a difference between 7 and 7.5 when using autogen keys.
The solution here is rather obvious once you know the background, either you manually generate a key, rather than using an autogen one, or you change the identity of the application pool to the same user for each app pools.