2009-09-30 6 views
4

J'ai une application qui doit faire beaucoup d'usurpation d'identité, en raison du déplacement et de la création de nombreux fichiers sur des partages réseau protégés. J'ai créé une classe statique simple qui a une méthode qui prend un utilisateur, un domaine, un mot de passe et un délégué qui contient le code dont vous avez besoin dans le contexte de l'emprunt d'identité.Liaison d'assembly sous WindowsImpersonationContext. Comment empêcher FileLoadException?

Le problème que j'ai rencontré est lorsque le CLR tente de se lier à un assembly référencé dans ce contexte. Une exception FileLoadException est lancée avec un message "Accès refusé".

Je suis amené à croire que cela est dû au fait que l'utilisateur dont l'identité est empruntée ne dispose pas de privilèges suffisants pour le fichier * .DLL sous le système de fichiers. Par exemple, je peux écrire du code bénin juste avant le bloc d'emprunt d'identité, qui ne fait rien d'autre que de charger les types de l'assembly problème avant que le contexte ne bascule vers l'utilisateur emprunté, et cela fonctionne très bien! Cependant je ne considère pas vraiment que ce soit une solution élégante - est-ce que je vais devoir commencer à m'inquiéter des types que je peux employer sous l'emprunt d'identité, m'assurant que j'ai mis au hasard des déclarations typeof() au préalable?

Ce qui rend cela plus frustrant, c'est que je ne rencontre pas ce problème sur ma machine de développement local. C'est lorsque les assemblys sont envoyés à l'environnement bêta que ce problème se produit. Et je n'ai pas accès à lire les autorisations de fichier de l'environnement bêta pour essayer de les imiter sur ma machine de localisation.

Dans tous les cas, j'ai essayé cette solution:

// Defined above: 
// System.Security.Principal.WindowsIdentity identity; 
// System.Security.Principal.WindowsImpersonationContext context; 

context = identity.Impersonate(); 

int tries = 0; 
while (true) 
{ 
    try 
    { 
     contextAction(); 
    } 
    catch (FileLoadException ex) 
    { 
     if (tries > MAX_TRIES) 
     { 
      // don't allow an infinite loop 
      throw; 
     } 
     if (String.IsNullOrEmpty(ex.FileName)) 
     { 
      // if this is null/empty, we can't really recover 
      throw; 
     } 
     context.Undo(); // return to current logon 
     try 
     { 
      var assemblyName = new AssemblyName(ex.FileName); 
      Assembly.Load(assemblyName); 
      tries++; 
      continue; 
     } 
     finally 
     { 
      context = identity.Impersonate(); // re-impersonate 
     } 
    } 
    finally 
    { 
     // return to your current windows logon 
     context.Undo(); 
    } 
} 

Pas de dés. Je reçois toujours l'exception «Accès refusé», sauf maintenant à partir de la ligne commençant par Assembly.Load.

Une chose intéressante à noter est que j'obtenais la même exception du serveur de construction. Cette solution ci-dessus l'a corrigé sur le serveur de construction. Pas dans notre environnement bêta.

Qu'est-ce qui me manque ici? Merci.

Répondre

0

Je ne sais pas quel est le problème, mais Windows Impersonation ne fonctionne pas bien lorsque l'on emprunte l'identité d'un administrateur à partir d'un compte d'utilisateur non administrateur. Il se peut que votre utilisateur final soit un non administrateur & lorsque vous essayez d'usurper l'identité, il échoue menant à une erreur d'accès au fichier.

3

J'ai le même problème. Cela semble être un problème avec la "session" d'emprunt d'identité qui n'est pas nettoyée correctement. Chargement de l'assembly problème avant d'appeler votre logique fonctionne correctement. Tenter de charger l'assembly après avoir annulé et mis au rebut l'identité d'emprunt d'identité et le contexte entraîne une autre exception FileLoadException.

Another thread montre un exemple de code où ils ferment les poignées de jeton, mais cela n'a fait aucune différence dans mon code de test.

EDIT

Appel System.Security.Principal.WindowsIdentity.GetCurrent() avant et après le code d'emprunt d'identité renvoie les mêmes informations, même si quelque chose doit être changé pour ne plus permettre à l'ensemble des problèmes à charger .

EDIT # 2 (MAINTENANT AVEC 100% PLUS SOLUTION!)

Nous venons de découvrir un autre problème, beaucoup plus sérieux dans notre application web.Le processus de création d'une identité et de fermeture du handle n'était pas correct. Nous avions des problèmes majeurs dans notre application multi-thread, qui a finalement amené notre site Web à un arrêt de broyage lorsque toutes les poignées ont manqué. Après un peu de discussion avec les autres développeurs et la recherche en ligne (y compris les conseils de l'avant-dernier post dans this thread), j'ai amélioré le code afin que les poignées de jeton sont correctement nettoyés.

Cela semble avoir également résolu notre problème de chargement d'assemblys dans un contexte d'emprunt d'identité. Je n'arrive pas à reproduire l'erreur maintenant, peu importe combien j'essaie. Je vais poster notre code d'emprunt d'identité amélioré ici, ainsi vous pouvez voir si cela fonctionne dans votre application. Notez le bloc de verrouillage dans GetIdentity; C'est très important pour une application multi-thread.

// LogonType = 8  // LOGON32_LOGON_NETWORK_CLEARTEXT 
// LogonProvider = 0 // LOGON32_PROVIDER_DEFAULT 

[DllImport ("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
private static extern bool LogonUser(string userName, string domain, 
    string password, int logonType, int logonProvider, ref IntPtr accessToken); 

[DllImport ("kernel32.dll", SetLastError = true)] 
private static extern bool CloseHandle(IntPtr handle); 

private static readonly object Locker = new Object(); 

private static WindowsIdentity GetIdentity(string username, string domain, string password) 
{ 
    lock (Locker) 
    { 
     IntPtr token = IntPtr.Zero; 
     if (LogonUser (username, domain, password, 
      (int) LogonType, (int) LogonProvider, ref token)) 
     { 
      // using the token to create an instance of WindowsIdentity class 
      var identity = new WindowsIdentity (token); 
      CloseHandle (token); // the WindowsIdentity object duplicates this token internally 
      return identity; 
     } 

     throw new SecurityException (string.Format (
      "Invalid username/password (domain: '{0}', username: '{1}')", 
      domain, username)); 
    } 
} 

public static T ExecuteAction<T>(string username, string domain, string password, 
    Func<T> contextAction) 
{ 
    var identity = GetIdentity (username, domain, password); 
    var context = identity.Impersonate(); 
    try 
    { 

     return contextAction(); 
    } 
    finally 
    { 
     context.Undo(); 
     context.Dispose(); 
    } 
} 
0

Vous pouvez mettre les assemblages 'offensants' dans le GAC.

Ou ajouter de façon dynamique héritable Read & Autoriser l'utilisateur à se faire passer pour l'identité du répertoire contenant les assemblys juste avant d'emprunter l'identité de l'utilisateur. Je suppose que vous contrôlez l'emplacement des assemblées offensantes?

Questions connexes