Getting into the Hive mind - IIS, Application Pools and Process Account Registry Access
I came across an interesting little issue the other day which I thought I'd share with you in case any of you experience a similar problem.
I was working with an ASP .NET application we have produced. For reasons that are too boring to explain the application has to asynchronously call out to an 3rd-party command line utility to perform some processing as part of its operations. I used the .NET Process type to execute the 3rd-party utility in a separate process.
When I built the application on my laptop and ran it under the Visual Studio development Web server everything worked as expected and the 3rd party utility was invoked correctly to do what it needed to do. However when I deployed the application to the staging server running IIS the 3rd-party application started correctly but then failed with an error code before it could complete its operation.
On the staging server the application pool for this application is configured to run under a specific domain account. I logged in to the staging server using this account and verified that I could run the utility correctly from the command line, which I could. Whilst I was still logged in with this account I tried accessing the ASP .NET application again and this time it worked correctly with the 3rd-party utility completed its processing without error.
It took me some time (and a lot of reading of Keith Brown's excellent The .NET Developers Guide to Windows Security book) to figure out what was going on. The fact that it worked when I was logged in with the application pool account made me suspect that it had something to do with the user profile for that account. After reading Keith's book I deduced that Windows does not load the user profile (HKEY_CURRENT_USER hive) for the user when it is impersonating an account and that IIS seems to use impersonation for an application pool account. This means that IIS does not cause the profile to be loaded for the account under which the application pool runs, probably as a performance optimisation. This is different to the behaviour of Windows services; when you configure a Windows service to run under a particular account context it does load the profile for that account.
When an application running in the application pool starts a new process it does so under the context of the application pool account which does not have a profile loaded. This was important in my case as it turns out that the 3rd-party application needs to read a registry key from the HKEY_CURRENT_USER hive to operate correctly, which requires the profile to be loaded.
So what's the solution? There is a Win32-API LoadUserProfile function which can be called to force a user profile to be loaded but since XP SP2/Server 2003 this function can only be called from an administrative account. Running my ASP .NET application under an administrative account was not an acceptable solution but there is a simple alternative. From reading Keith's book I found out that whenever any logon session causes a user profile to be loaded, that user profile becomes available to all other logon sessions on the machine. This means that a process started using impersonation can access the profile if another login session has caused the profile to be loaded. The way I achieved this was to write a Windows service which executes under the same account as the ASP .NET application and does nothing but periodically check to see if it needs to terminate. Simply running this service causes the profile to be loaded so that the 3rd-party utility will execute correctly when started by the ASP .NET application. I set the service to start automatically so that it should always be running when the server starts and, hey presto, the ASP .NET application know works correctly all the time.
del.ico.us |
Digg It |
Technorati |
StumbleUpon |
Furl |
reddit