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.

Comments

  • Anonymous
    September 17, 2009
    Short and sharp. I faced the same issue but with Winclient .I fixed it with Fix#2

  • Anonymous
    September 17, 2009
    Smart trick !!! Is this method recommended in real scenario? just wondering if it is violating any the security rules. Thanks B. Mavi

  • Anonymous
    September 20, 2009
    In this situation, I use HostingEnvironment.Impersonate()  which is effectively the same, however, you can also use HostingEnvironment.IsHosted to check if the code is running in hosted environment. See http://bit.ly/18mHkQ

  • Anonymous
    September 20, 2009
    Do you really want your IIS worker process account running with permissions to access a database? Configure your service to run under a distinct identity so that identity can be used for authentication against the database. Have a look at a technique called a trusted sub-system. Each sub-system in this architecture only authenticates its immediate caller, and fully trusts its caller to authenticate its up-stream callers. WCF automatically propagates the authenticated security context/token across calls.  Each sub-system just has to perform authorisation to allow access to secure resources.

  • Anonymous
    September 21, 2009
    The comment has been removed