2010-06-10 9 views
3

J'utilise DirectoryServices et le fournisseur WinNT: // pour me connecter à un ordinateur distant. Je vérifie ensuite certaines informations d'appartenance à un groupe et éventuellement j'ajoute ou supprime un utilisateur de domaine d'un groupe local spécifié.Connexion à un ordinateur distant à l'aide de WinNT: // Fournisseur et services d'annuaire Ignore le nom d'utilisateur/mot de passe

J'ai pu faire fonctionner tout ce code sans problème en utilisant une application de console vb.net et en communiquant avec ma boîte locale, ou avec n'importe quelle boîte où le compte auquel je suis connecté dispose de droits administratifs.

code:

string strUserPath = "WinNT://DomainName/someuser,user"; 
    DirectoryEntry deComputer = new DirectoryEntry("WinNT://" + Computername + ",computer"); 
    deComputer.RefreshCache(); 
    DirectoryEntry deGroup = deComputer.Children.Find("administrators", "group"); 

    IEnumerable members = deGroup.Invoke("members", null); 
    List<DirectoryEntry> r = new List<DirectoryEntry>(); 

    foreach (object o in members) 
    { 
     DirectoryEntry deMember = new DirectoryEntry(o); 

     r.Add(deMember); 
    } 

    deGroup.Invoke("Add", strUserPath); 
    deGroup.CommitChanges(); 

    deGroup.Invoke("Remove", strUserPath); 
    deGroup.CommitChanges(); 

Je déplacé le code à une application web ASP.Net, qui usurpe l'identité d'un compte de service dans la section Impersonate de web.config. Le compte que je suis se faisant passer pour ne pas les droits d'administrateur sur l'un des postes de travail, donc je mets un nom d'utilisateur/mot de passe dans le constructeur pour l'entrée d'ordinateur comme ceci:

DirectoryEntry deComputer = new DirectoryEntry("WinNT://" + Computername + ",computer", username, password); 

Le nom d'utilisateur est celui d'un compte de domaine qui a droits d'administration locaux sur chaque poste de travail. Si je regarde la propriété Username de l'objet deComputer résultant, je peux voir que le nom d'utilisateur correspond à ce que j'ai entré. De plus, si je saisis un mot de passe invalide, une erreur se produit, de sorte qu'il s'authentifie d'une manière ou d'une autre.

Toutefois, si j'essaie maintenant d'ajouter ou de supprimer un utilisateur d'un poste de travail distant, j'obtiens une erreur d'accès général refusée. Si j'ajoute le compte de service qu'ASP.Net utilise en tant qu'administrateur local sur ce poste de travail, il ajoutera et supprimera aucun problème. J'ai ensuite essayé d'utiliser LogonAPI (appel advapi32.dll -> LogonUser) pour me connecter en tant que compte utilisateur administrateur local sur toutes les stations de travail, usurpé l'identité WindowsIdentitiy résultante et essayé d'exécuter l'instanciation deComputer d'origine. Quand je fais ceci chaque propriété, sauf le chemin, renvoie une exception OLE ...

Je suis assez perdu ici sur ce qu'il faut essayer ensuite. Toute aide serait grandement appréciée.

--Workaround--

Pour contourner le problème que nous avons créé un service Windows qui fonctionne sous le compte administrateur local et n'a donc pas eu de problèmes en cours d'exécution du code. Nous poussons toutes nos mises à jour vers une table dans une base de données SQL et le service les récupère et les traite. MAIS, je voudrais vraiment vraiment savoir pourquoi cela ne fonctionne pas, et ce serait bien de pousser les mises à jour directement à partir du site Web.

Répondre

1

Avez-vous essayé d'utiliser AuthenticationTypes.Secure comme paramètre supplémentaire de DirectoryEntry après le nom d'utilisateur et le mot de passe? Par ailleurs si vous voulez vous connecter à un ordinateur distant, vous ne devriez pas utiliser LogonUser. API correcte sont WNetAddConnection2 (voir http://msdn.microsoft.com/en-us/library/aa385413.aspx) ou NetUseAdd (voir http://msdn.microsoft.com/en-us/library/aa370645.aspx)

+0

J'ai essayé AuthenticationTypes.Secure, mais sans succès. J'ai lu les descriptions principales sur MSDN et il ne semble pas que WNetAddConnection2 et NetUseAdd fonctionneront pour toutes les situations. Aussi, comment pourrais-je les utiliser avec un DirectoryEntry? Je n'ai pas vu de manière simple dans l'article MSDN, pas comme c'est facile quand vous utilisez Logonuser. – Peter

+0

La fonction 'LogonUser' permet une connexion locale, mais vous devez avoir une connexion à distance. Si vous voulez, par exemple, accéder à une banque avec HTTPS, vous ne pouvez pas passer un appel à "LogonUser" avec votre compte bancaire, mais vous vous connectez uniquement à distance sur l'ordinateur de destination. La même chose fonctionne ici. Si l'ordinateur de destination n'a pas confiance à l'ordinateur source ou si vous essayez de vous connecter avec un compte d'utilisateur existant (localement) uniquement sur l'ordinateur de destination "LogonUser" avec emprunt d'identité CAN NOT WORK! Vous pouvez utiliser 'WNetAddConnection2' ou' NetUseAdd' sans aucun problème. – Oleg

+1

Si vous établissez une connexion à un ordinateur de destination en respectant 'WNetAddConnection2' ou' NetUseAdd', il sera utilisé pour d'autres tentatives d'accès à l'ordinateur distant. Aussi 'DirectoryEntry' avec le fournisseur' WinNT' l'utilisera. Pour vous déconnecter, vous pouvez utiliser 'WNetCancelConnection2' ou' NetUseDel'. Vous trouverez d'autres explications sous http://stackoverflow.com/questions/3282927/manage-remote-service-using-alternate-credentials/3348967#3348967. Je vous recommande d'essayer 'WNetAddConnection2' et' WNetCancelConnection2' et vous verrez qu'ils font exactement ce dont vous avez besoin. – Oleg

0

Depuis c'est une question populaire, j'ai séparé la réponse à et converti le code C#

Voici le code final travaillé pour moi. Cela utilise WNetAddConnection2 pour établir une connexion en premier, avant d'utiliser DirectoryEntry.

public static class CredentialSetter 
{ 
    public static void SetCredentials() 
    { 
     string Computername = "SomeComputer"; 
     //Create connection to remote computer' 
     using (NetworkConnection nc = new NetworkConnection("\\\\" + Computername + "", new NetworkCredential("Domain\\Login", "Password"))) 
     { 
      //try connecting using DirectoryEntry to the same machine and add me as a user' 
      string strUserPath = string.Format("WinNT://{0}/{1},user", "DOMAIN", "USER"); 
      DirectoryEntry deGroup = new DirectoryEntry("WinNT://" + Computername + "/Administrators"); 
      deGroup.RefreshCache(); 

      //add and remove the user from the group' 
      deGroup.Invoke("Add", strUserPath); 
      deGroup.CommitChanges(); 
      Console.WriteLine("User Added to computer " + Computername); 

      deGroup.Invoke("Remove", strUserPath); 
      deGroup.CommitChanges(); 
      Console.WriteLine("User Removed from computer " + Computername); 

      deGroup.Close(); 
     } 
     Console.ReadLine(); 
    } 

    public class NetworkConnection : IDisposable 
    { 
     private string _networkName; 
     public NetworkConnection(string networkName, NetworkCredential credentials) 
     { 
      _networkName = networkName; 

      dynamic netResource = new NetResource 
      { 
       Scope = ResourceScope.GlobalNetwork, 
       ResourceType = ResourceType.Disk, 
       DisplayType = ResourceDisplaytype.Share, 
       RemoteName = networkName 
      }; 

      dynamic result = WNetAddConnection2(netResource, credentials.Password, credentials.UserName, 0); 

      if (result != 0) 
      { 
       throw new IOException("Error connecting to remote share", result); 
      } 
     } 

     ~NetworkConnection() 
     { 
      Dispose(false); 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 

     protected void Dispose(bool disposing) 
     { 
      WNetCancelConnection2(_networkName, 0, true); 
     } 

     [DllImport("mpr.dll")] 
     private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags); 

     [DllImport("mpr.dll")] 
     private static extern int WNetCancelConnection2(string name, int flags, bool force); 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public class NetResource 
    { 
     public ResourceScope Scope; 
     public ResourceType ResourceType; 
     public ResourceDisplaytype DisplayType; 
     public int Usage; 
     public string LocalName; 
     public string RemoteName; 
     public string Comment; 
     public string Provider; 
    } 

    public enum ResourceScope : int 
    { 
     Connected = 1, 
     GlobalNetwork, 
     Remembered, 
     Recent, 
     Context 
    } 

    public enum ResourceType : int 
    { 
     Any = 0, 
     Disk = 1, 
     Print = 2, 
     Reserved = 8 
    } 

    public enum ResourceDisplaytype : int 
    { 
     Generic = 0x0, 
     Domain = 0x1, 
     Server = 0x2, 
     Share = 0x3, 
     File = 0x4, 
     Group = 0x5, 
     Network = 0x6, 
     Root = 0x7, 
     Shareadmin = 0x8, 
     Directory = 0x9, 
     Tree = 0xa, 
     Ndscontainer = 0xb 
    } 
} 
+0

J'ai essayé la méthode ci-dessus.Mais encore je reçois l'erreur Accès refusé même lorsque je passe les informations d'identification correctes. –

-1

Erreur (0x80004005): Erreur non spécifiée

J'ai eu le problème de connexion certains aux fenêtres à distance avec l'erreur d'erreur (0x80004005): Erreur non spécifiée. J'ai résolu comme suit:

//Define path 
//This path uses the full path of user authentication 
String path = string.Format("WinNT://{0}/{1},user", server_address, username); 
DirectoryEntry deBase = null; 
try 
{ 
    //Try to connect with secure connection 
    deBase = new DirectoryEntry(path, username, _passwd, AuthenticationTypes.Secure); 

    //Connection test 
    //After test define the deBase with the parent of user (root container) 
    object nativeObject = deBase.NativeObject; 
    deBase = deBase.Parent; 

} 
catch (Exception ex) 
{ 
    //If an error occurred try without Secure Connection 
    try 
    { 
     deBase = new DirectoryEntry(path, username, _passwd); 

     //Connection test 
     //After test define the deBase with the parent of user (root container) 
     object nativeObject = deBase.NativeObject; 
     deBase = deBase.Parent; 
     nativeObject = deBase.NativeObject; 

    } 
    catch (Exception ex2) 
    { 
     //If an error occurred throw the error 
     throw ex2; 
    } 
} 

Espérons que cela aide. Helvio Junior www.helviojunior.com.br