TPL Task in WCF service fails to use correct IIS security Credentials (SQL Connection)

Go To StackoverFlow.com

4

I have a WCF service method that calls a SQL stored proc. I'm developing using IIS 5 (can't do much about that, II6/7 not available)

To get some gains, I'm doing a number of async calls to this stored proc by putting the call into a c# TPL Task.

When run as a Task, I'm getting an SQL Exception... "Login failed. The login is from an untrusted domain and cannot be used with Windows authentication"

However, If I run the exact same process without using a Task, I have no problems with SQL connection

It would appear to me that the credentials for the IIS Virtual folder (WCF) are not being delegated to the Task? Any ideas how I can specificy credentials for the TPL Task thread, ie to use the same as the parent etc ?

I am using Windows Authentication (sspi), and impersonation to be able to connect to the seperate SQL box.

Your help appreciated.

2012-04-04 08:33
by Ron Weston
are you using windows authentication - Aliostad 2012-04-04 08:35
I mean windows authentication for IIS - Aliostad 2012-04-04 08:53
Yes, I am using windows auth for IIS, and SQL connect string specifies SSPI etc - Ron Weston 2012-04-04 08:57
Sorry, Is SQL on a different box - Aliostad 2012-04-04 09:05
yep, IIS on one box, SQL on another. As I say without using TPL the connection is fine - Ron Weston 2012-04-04 09:50


5

You have two choices.

1) Opt your entire application into always flowing the identity using:

<runtime>
    <alwaysFlowImpersonationPolicy enabled="true"/>
</runtime>

This has a side effect of overhead and the danger of accidentally executing some unintended code with the priviledges of the currently calling user rather than the application identity. I would personally avoid this and go with #2 where you explicitly opt-in.

2) Capture the WindowsIdentity before setting up your TPL tasks and explicitly impersonate where you need to make the calls using Impersonate + WindowsImpersonationContext:

public void SomeWCFOperation()
{
    WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();

    Task.Factory.StartNew(() =>
    {
         // some unpriviledged code here


         using(WindowsImpersonationContext impersonationContext = currentIdentity.Impersonate())
         {
            // this code will execute with the priviledges of the caller
         }

         // some more unpriviledged code here
    });  
}
2012-04-06 16:03
by Drew Marsh
Hi Drew. Good clear answer, glad you understood my issue straight off. I wont be able to try this solution until after Easter, but as soon as I do I'll mark this question as answered. You must spend your 50 bonus points wisely though I might add ;- - Ron Weston 2012-04-07 16:48
Yep, I can confirm this works fine (well the option 2). Thanks agai - Ron Weston 2012-04-11 13:40
Glad to help. Happy coding - Drew Marsh 2012-04-11 16:53
Hmm. Option 1 doesn't seem to work for me (configured via Web.config) - only Option 2 works, but I was hoping to avoid having to propagate the identity down through several layers of threading - lesscode 2012-07-12 14:56
I see what's happening. In my case I'm WAS-hosting a WCF service. The web.config configuration is not taking effect - I have to either edit the global aspnet.config, or set a custom CLRConfigFile on my App Poo - lesscode 2012-07-12 17:07
Yeah, CLRConfigFile on the AppPool should help you there - Drew Marsh 2012-07-12 18:01


0

As another workaround, you can create extensions to the TPL as follows:

public static class TaskFactoryExtensions
{
    public static Task StartNewImpersonated(this TaskFactory taskFactory, Action action)
    {
        var identity = WindowsIdentity.GetCurrent();
        return taskFactory.StartNew(() =>
        {
            using (identity.Impersonate()) 
            {
                action();
            }
        });
    }

    public static Task<TResult> StartNewImpersonated<TResult>(this TaskFactory taskFactory, Func<TResult> function)
    {
        var identity = WindowsIdentity.GetCurrent();
        return taskFactory.StartNew<TResult>(() =>
        {
            using (identity.Impersonate())
            {
                return function();
            }
        });
    }
}

You would then call these new methods in place of the standard StartNew methods.

The downside to this is that there are a lot of methods to override.

2012-08-30 14:31
by Andy Cohen
Ads