Question

I hope you can help me.

I am doing some webrequests within my C# 4.0 application which require authentication. I simply use the CredentialsCache.DefaultCredentials. This works great as long as I do not run the functionality in a different thread / task via Task<T>.Factory.StartNew(...). I then get 401 errors. I assume that the credentials are not passed through to child threads?

How can I pass through the credentials to any child tasks / threads?

No correct solution

OTHER TIPS

I assume that you are using impersonation and that the problem is that the credentials are not being flowed into the Task. It's worth checking this point to save a wild goose chase by dumping out the value of Windows.Identity.GetCurrent().Name in both the initiating code and the Task body and making sure it's what you expect.

So given the above, there are a couple of ways that (to put it formally) execution context (or just security context) is not being flowed across threads. The default behaviour is that context is flowed - so something must be affecting that.

1) Something has set ExecutionContext.SuppressFlow() - you can check this by dumping the value of ExecutionContext.IsFlowSuppressed() inside the task.

2) There is a configuration element <legacyImpersonationPolicy> (conifguration->runtime->legacyImpersonationPolicy) that defaults to false. When false, WindowsIdentity is flowed across asychronous points. When true it is not. This is regardless of the ExecutionContext flow settings. So true here would cause a problem for you. You can check this by dumping the value of SecurityContext.IsWindowsIdentityFlowSuppressed() is your task. This can also be programmatically set per thread with SecurityContext.SuppressFlowWindowsIdentity().

Finally, for completeness, in case you are using unmanaged code there is another setting <alwaysFlowImpersonationPolicy> that controls how impersonated credentials are flowed in unmanaged scenarios as well; the other settings described only affect managed code.

In case someone else comes across this issue... mine was a little different. My WCF service is exposed as a REST service as well as a SOAP, with the security context coming from either System.Web.HttpContext.Current or System.ServiceModel.OperationContext.Current. My DAL uses one of those contexts to identify the current user by checking HttpContext.Current.User.Identity or OperationContext.Current.ClaimsPrincipal.Identity.

So for my case, I had to save those two contexts in variables outside of the parallel foreach and then set them inside the parallel to the saved values. That seemed to do the trick. The same concept could work for other TPL situations with some modifications.

var httpcontext = System.Web.HttpContext.Current;
var opcontext = System.ServiceModel.OperationContext.Current;
Parallel.ForEach(types, (p) =>
{
    System.Web.HttpContext.Current = httpcontext;
    System.ServiceModel.OperationContext.Current = opcontext;

    // DO YOUR PARALLEL PROCESSING HERE
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top