web-dev-qa-db-fra.com

Comment puis-je convertir un SID en un nom de compte en C #

J'ai une application C # qui scanne un répertoire et rassemble des informations. Je souhaite afficher le nom du compte pour chaque fichier. Je peux le faire sur le système local en obtenant le SID de l'objet FileInfo, puis en faisant:

string GetNameFromSID( SecurityIdentifier sid )
{
    NTAccount ntAccount = (NTAccount)sid.Translate( typeof( NTAccount ) );
    return ntAccount.ToString();
}

Cependant, cela ne fonctionne pas pour les fichiers sur un réseau, probablement parce que la fonction Translate () ne fonctionne qu'avec les comptes d'utilisateurs locaux. J'ai pensé que je pourrais peut-être faire une recherche LDAP sur le SID, j'ai donc essayé ce qui suit:

string GetNameFromSID( SecurityIdentifier sid )
{
    string str = "LDAP://<SID=" + sid.Value + ">";
    DirectoryEntry dirEntry = new DirectoryEntry( str );
    return dirEntry.Name;
}

Cela semble fonctionner, dans la mesure où l'accès à "dirEntry.Name" se bloque pendant quelques secondes, comme s'il s'éteignait et interrogeait le réseau, mais il levait ensuite une System.Runtime.InteropServices.COMException

Quelqu'un sait-il comment obtenir le nom de compte d'un fichier arbitraire ou d'un SID? Je ne connais pas grand-chose au réseautage ou LDAP ou quoi que ce soit. Il y a une classe appelée DirectorySearcher que je suis peut-être censé utiliser, mais elle veut un nom de domaine, et je ne sais pas comment l'obtenir non plus - tout ce que j'ai est le chemin d'accès au répertoire que je scanne.

Merci d'avance.

51
Sam Hopkins

La méthode Translate de l'objet SecurityReference fonctionne sur les SID non locaux mais uniquement pour les comptes de domaine. Pour les comptes locaux sur une autre machine ou dans une configuration hors domaine, vous devez PInvoke la fonction LookupAccountSid en spécifiant le nom de la machine spécifique sur laquelle la recherche doit être effectuée.

18
Stephen Martin

Voir ici pour une bonne réponse:

La meilleure façon de résoudre le nom d'utilisateur d'affichage par SID?

L'essentiel est le suivant:

string sid="S-1-5-21-789336058-507921405-854245398-9938";
string account = new System.Security.Principal.SecurityIdentifier(sid).Translate(typeof(System.Security.Principal.NTAccount)).ToString();

Cette approche fonctionne pour moi pour les SID non locaux sur Active Directory.

39
Chris

System.DirectoryServices.AccountManagement.UserPrincipal class ( lien msdn ) a une fonction statique FindByIdentity pour convertir un SID en objet User. Il doit pouvoir fonctionner à la fois sur la machine locale ou sur un serveur LDAP/Active Directory. Je ne l'ai utilisé que contre Active Directory.

Voici un exemple que j'ai utilisé dans IIS:

// Set the search context to a specific domain in Active Directory
var searchContext = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=SomeOU,DC=YourCompany,DC=com");
// get the currently logged in user from IIS
MembershipUser aspUser = Membership.GetUser();
// get the SID of the user (stored in the SecurityIdentifier class)
var sid = aspUser.ProviderUserKey as System.Security.Principal.SecurityIdentifier;
// get the ActiveDirectory user object using the SID (sid.Value returns the SID in string form)
var adUser = UserPrincipal.FindByIdentity(searchContext, IdentityType.Sid, sid.Value);
// do stuff to user, look up group membership, etc.
6
Bakanekobrain

En C #, récupérez le SID de l'utilisateur et affectez-le à une variable de chaîne via:

string strUser = System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString();

Vous devrez utiliser une chaîne car la capacité de résolution vers le nom d'utilisateur prend en charge la chaîne. En d'autres termes, l'utilisation de var varUser entraînera une erreur d'espace de noms.

string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString();
3
J Weezy

Génial. J'ai ajouté du code LookupAccountSid () à partir d'ici:

http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid

Et cela a fonctionné, même si j'ai dû fournir le nom de l'hôte moi-même. Dans le cas d'un chemin UNC, je peux simplement en prendre le premier composant. Quand c'est un lecteur mappé, j'utilise ce code pour convertir le chemin en UNC:

http://www.wiredprairie.us/blog/index.php/archives/22

Cela semble fonctionner, alors c'est comme ça que je vais le faire, sauf si quelqu'un arrive avec une situation dans laquelle le premier composant d'un chemin UNC n'est pas le nom d'hôte ...

Merci à tous pour votre aide.

1
Sam Hopkins

Ooh, alors il est possible que l'appel LDAP ne fonctionne pas car vous pourriez ne pas être dans un environnement Active Directory. Si tel est le cas, chacune de vos machines est responsable de son propre magasin d'identité. Et votre premier exemple de code ne fonctionne pas sur le réseau car la machine sur laquelle vous exécutez votre code ne sait pas comment résoudre le SID qui n'a de sens que sur la machine distante.

Vous devriez vraiment vérifier si vos machines font partie d'un Active Directory. Vous le saurez pendant le processus de connexion. Ou vous pouvez vérifier en faisant un clic droit sur "Poste de travail", sélectionnez "Propriétés", l'onglet "Nom de l'ordinateur", puis voyez si votre ordinateur fait partie d'un domaine.

1
barneytron

Vous pouvez également obtenir le nom de compte de comptes spéciaux comme "Tout le monde" avec un code comme celui-ci qui fonctionnera indépendamment des paramètres de langue de l'utilisateur:

   SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
   string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();
1
jm.

Obtenez le domaine actuel:

System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain();

Obtenez une entrée de répertoire de ldap et le nom de domaine:

DirectoryEntry de = new DirectoryEntry(string.Format("LDAP://{0}", domain));

Obtenez le Sid d'un ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

ActiveDirectoryMembershipUser user = (ActiveDirectoryMembershipUser)Membership.GetUser();
var sid = (SecurityIdentifier)user.ProviderUserKey;

Obtenez le nom d'utilisateur de SecurityIdentifier:

(NTAccount)sid.Translate(typeof(NTAccount));

Effectuez la recherche de répertoire sur un répertoire activé avec l'entrée de répertoire de domaine et le nom d'utilisateur:

DirectorySearcher search = new DirectorySearcher(entry);
        search.Filter = string.Format("(SAMAccountName={0})", username);
        search.PropertiesToLoad.Add("Name");
        search.PropertiesToLoad.Add("displayName");
        search.PropertiesToLoad.Add("company");
        search.PropertiesToLoad.Add("homePhone");
        search.PropertiesToLoad.Add("mail");
        search.PropertiesToLoad.Add("givenName");
        search.PropertiesToLoad.Add("lastLogon");
        search.PropertiesToLoad.Add("userPrincipalName");
        search.PropertiesToLoad.Add("st");
        search.PropertiesToLoad.Add("sn");
        search.PropertiesToLoad.Add("telephoneNumber");
        search.PropertiesToLoad.Add("postalCode");
        SearchResult result = search.FindOne();
        if (result != null)
        {
            foreach (string key in result.Properties.PropertyNames)
            {
                // Each property contains a collection of its own
                // that may contain multiple values
                foreach (Object propValue in result.Properties[key])
                {
                    outputString += key + " = " + propValue + ".<br/>";
                }
            }
        }

Selon les données de votre Active Directory, vous obtiendrez une réponse variée dans la sortie.

Voici un site qui possède toutes les propriétés utilisateur dont j'avais besoin:

0
tombmedia

Celui-ci est un stumper. Vous êtes dans un environnement Active Directory, non? Je vérifie juste :)

Quoi qu'il en soit, au lieu de lier avec sid.Value,

string str = "LDAP://<SID=" + sid.Value + ">";

J'essaierais de convertir le tableau d'octets du SID en Octet String et de le lier à la place.

Il y a un bon exemple ici à la page 78. Cela vous rapprochera. Pour être honnête, je n'ai jamais essayé de lier avec un SID auparavant. Mais j'ai réussi la liaison avec un utilisateur GUID cependant :)

Bonne chance et tiens-moi au courant pour me dire comment ça s'est passé.

0
barneytron