0

In my C# application, I use Impersonation to extend access rights of users. For convenience, I just added a public static Impersonation object, which is initialized at App startup.

The code for Impersonation is from this answer on stackoverflow. Executing any code in the app so far works fine:

someCodeThatNeedsImpersonation(); // Fine
somethingElse();

I now want to move code into a BackgroundWorker:

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (s, a) =>
{
    someCodeThatNeedsImpersonation(); // fails to "see" impersonation
}
bw.RunWorkerCompleted += (s, a) =>
{
    somethingElse();
}
bw.RunWorkerAsync();

This fails, because apparently the Impersonation handle that was initialized in the main thread is not used in the BackgroundWorker.

A quick fix, of course, is

bw.DoWork += (s, a) =>
{
    using ( new Impersonation(...) )
    {
        someCodeThatNeedsImpersonation(); // works, because of bw's own impersonation
    }
}

but I would prefer a solution that doesn't need a new Impersonation handle in every BackgroundWorker (because I will surely forget one). Is there a way to share the static Impersonation object of the main thread?

Community
  • 1
  • 1
  • 1
    This is about ASP .NET, but the reason and solutions are the same: http://blogs.msdn.com/b/tom/archive/2008/04/22/making-an-asynchronous-call-using-the-impersonation-identity.aspx – Dennis Dec 29 '15 at 10:40
  • Also this may help: http://blog.iamandycohen.com/2012/09/17/await-async-mvc-and-impersonation/ – Dennis Dec 29 '15 at 10:42
  • @Dennis thanks for the links. Method 2 of the first link (http://blogs.msdn.com/b/tom/archive/2008/04/22/making-an-asynchronous-call-using-the-impersonation-identity.aspx) works flawlessly. Would you like to post this as an answer? – random string Dec 29 '15 at 11:10
  • Well, there are no my investments in the answer, so, feel free to post answer yourself. Besides, the question as it stated, is a ground for wide discussion - since this is desktop application (I assume it from using `BackgroundWorker`), it's a big question, why do you need so many places to impersonate. So, the solution you accepted doesn't look good for me, because, IMO, it hides real design problems. – Dennis Dec 29 '15 at 11:41

2 Answers2

0

In Windows, the impersonation token is maintained for each thread separately, and isn't inherited when you create new threads.

The way to go is by impersonating just the code paths that need it, as you already showed with your using(...). The only difference, I'd say, was that instead of issuing .DoWork += { new Impersonation(...) } I would do something like this:

var bw = new BackgroundWorker();
bw.DoWork += Impersonated(TOKEN, (s, a) => { /* code */ });

Another approach, given that BackgroundWorker isn't sealed, and its OnDoWork() method is protected, would be to inherit the class and override OnDoWork() to impersonate. Then, you could do:

var bw = new ImpersonatingBackgroundWorker(...)
Yam Marcovic
  • 7,953
  • 1
  • 28
  • 38
  • I fully agree with "impersonation only where you need it", but that's how projects grow.. – random string Dec 29 '15 at 11:09
  • Yeah, well, you can use the lengthier impersonation but still reduce duplication, like in my example. The other thing you can do, noticing `BackgroundWorker` isn't a sealed class, and `OnDoWork()` is protected, is to inherit and override `OnDoWork()` to impersonate. Then just do `var bw = new ImpersonatingBackgroundWorker(...)`. But I personally like the example I gave--without inheritance--better. – Yam Marcovic Dec 29 '15 at 11:18
0

As mentioned on blogs.msdn.com, adding the following snippet to the App.config file is sufficient for Impersonation to cross thread bounds.

<configuration>
 <runtime>
   <alwaysFlowImpersonationPolicy enabled="true"/>
   <legacyImpersonationPolicy enabled="false"/>
 </runtime>
</configuration>

However, a best practice solution would only use impersonation where it is actually needed, rather than globally.