Impersonation, WCF, and making updates to a database

I was troubleshooting a problem with WCF where the updates to a remote database were failing.  The reason for the failure was found pretty quickly to be delegation.

For general impersonation questions in regards to WCF, there is lots of great information found here.

For my situation, the problem was that the ASP.NET application that was calling the WCF service was impersonating and I couldn’t enable delegation in my environment.  So the connection to SQL failed.  There are a number of ways to solve this problem, but some have more problems then others.

Fix #1

The easiest way is the add a User ID and Password to the web.config file.  But then you have to worry about updating that if the password expires and also the security of having the password in the config file.

Note: You can add the password to the registry following KB329290

Fix #2

Another option would be to impersonate a given user on the network that has permission and use that when you are making the calls to the database.  You can follow the “Impersonate a Specific User in Code” section of KB306158 for that.  This also has the problem of passwords expiring and that the password is stored in code, but it isn’t in a config file anymore.

Fix #3

The one I ended up using was this one.  In my case, the IIS Worker Process was already running under a network account that could assess the database.  So I just needed a way to get rid of the impersonation that the process was running under, do the database work, and then impersonate again.  The key was to do the following:

 WindowsImpersonationContext wic = null;
  
 try
 {
     wic = WindowsIdentity.Impersonate(IntPtr.Zero); // revert to self
  
     // Do database work here
 }
 finally
 {
     if (wic != null)
         wic.Undo(); // resume impersonating
 }

This will revert to self, let the database code run and then continue impersonating after that is done.

With this code, I don’t have to store any passwords in my code or config files.  And everything will work correctly.  The only drawback is that all database work is going through a single account and so on the database side, you can’t do auditing by users to see what they are doing.  But in my application, I am already logging information into the database so there would be no need to have that kind of information.