8

I am developing an application that needs to load plug-ins into separate child app domains. Only one plug-in is loaded into one child app domain. Each plug-in requires different Windows identity and those identities are different from the Windows identity used in default (parent) app domain. Each plug-in loads one or more of its child plug-ins.

E.g. Identity of default app domain is Authority\Limited (Authority is either domain name or machine name). Two plug-ins are loaded into two child app domains. The identities of the loaded plug-ins are Authority\Privileged1 and Authority\Privileged2. Authority\Privileged1 and Authority\Privileged2 have all necessary access to databases Database1 and Database2, respectively, whereas the Authority\Limited does not have access to any of aforementioned databases.

When creating child app domain, I call System.AppDomain.SetThreadPrincipal method passing System.Security.Principal.WindowsPrincipal instance. The instance was created from System.Security.Principal.WindowsIdentity instance created from duplicated user token (see http://support.microsoft.com/kb/306158). I have omitted the call to WindowsIdentity.Impersonate method since I am in default app domain while creating the WIndowsPrincipal instance.

I expected that setting the app domains thread principal would be sufficient for the loaded plug-ins to successfully log in to their respective databases and execute some T-SQL statements. To my surprise, the value returned by WindowsIdentity.GetCurrent() method is used when opening a connection to database. The value returned by the method is either process identity or impersonated identity.

Since the process identity does not have permissions necessary to work with the databases, it is not acceptable. Therefore, impersonation must come to play. However, impersonation must take place only in child app domains. Each plug-in exposes methods used to perform loading and unloading of the plug-in. I understand that I have to perform impersonation at the start and undo the impersonation at the end of those methods. However, the impersonation must be done for all threads spawned in the child app domains as well. Since each plug-in loads one or more of its child plug-ins and each plug-in might spawn one or more threads, the impersonation would have to be performed in many places, and that looks very messy.

Is it possible to perform impersonation only once so that affects all threads that are spawned in the child app domains?

  • 1
    You could consider using child processes instead of child domains and running these processes under the desired accounts. Explicitly setting up remoting will complicate things a little but presumably you already have an API in place that is suitable for remoting types. – Tim Lloyd Jan 29 '11 at 14:27
  • The application already supports running child processes under arbitrary identity. However, it must support same thing for child app domains. Thanks. –  Jan 29 '11 at 14:35

1 Answers1

3

No you can't do that - impersonation is per thread and the same thread can have code from several AppDomain on a call stack. This is especially true for plugin systems where main code (from some main AppDomain) calls plugin's logic in separate AppDomain.

Essentially you have to impersonate before calling plugin and revert when you are done. Note that if plugin uses threadpool for its own operations than it will need to impersonate properly.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Thanks, Alexei. Are there events that indicate a thread has been assigned to execute some code in an app domain and that a thread has finished the code execution? If there are such events, I could subscribe for them and perform impersonation and reversion in one place, respectfully. –  Jan 29 '11 at 20:28
  • I don't know. I never needed this, I would read on remoting and look through System.Runtime.Remoting namespace to find out. – Alexei Levenkov Jan 29 '11 at 21:52
  • Fair enough. Thanks for the suggestion. –  Jan 29 '11 at 23:05