2009-01-31 7 views
50

Mam aplikację C#, która skanuje katalog i zbiera pewne informacje. Chciałbym wyświetlić nazwę konta dla każdego pliku. Mogę to zrobić w systemie lokalnym poprzez uzyskanie SID dla obiektu FileInfo, a następnie robi:Jak przekonwertować z identyfikatora SID na nazwę konta w języku C#

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

Jednak to nie działa dla plików w sieci, przypuszczalnie dlatego, że Przekłada function() działa tylko z lokalne konta użytkowników. Pomyślałem, że mogę zrobić wyszukiwania LDAP na SID, więc próbowałem następujące:

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

To wydaje się to będzie działać, że dostęp do „dirEntry.Name” zawiesza się na kilka sekund, a jeśli się wyłącza i wysyła zapytanie do sieci, ale wtedy wyrzuca System.Runtime.InteropServices.COMException

Czy ktoś wie, jak mogę uzyskać nazwę konta dowolnego pliku lub identyfikatora SID? Nie wiem zbyt wiele na temat networkingu, LDAP czy czegokolwiek. Jest klasa o nazwie DirectorySearcher, której być może powinienem użyć, ale chce ona nazwy domeny i nie wiem, jak to uzyskać - wszystko, co mam, to ścieżka do skanowanego katalogu.

Z góry dziękuję.

+0

Czy istnieje szczególny komunikat, który pokazuje wyjątek COMException? –

+0

Może to być polityka grupowa pozwalająca na przechodzenie przez lokalną usługę katalogową, dlatego uzyskujesz wyjątek COM. Co pokazuje komunikat o błędzie? Spróbuj uruchomić filemona na maszynie sieciowej, dlaczego uzyskujesz dostęp do niego i zobaczyć wyniki. –

+0

Miałem na myśli "polityka grupowa nie pozwalająca ..." –

Odpowiedz

15

Metoda obiektu SecurityReference działa w przypadku nielokalnych identyfikatorów SID, ale tylko w przypadku kont domeny. W przypadku kont lokalnych na innym komputerze lub w ustawieniach innych niż domeny należy PInvoke funkcji LookupAccountSid określającej konkretną nazwę komputera, na którym należy wykonać wyszukiwanie.

+2

Właśnie zacząłem pisać jakiś kod, żeby zrobić coś podobnego i uznałem to za poprawne. P/Wywoływanie LookupAccountSid jest lepsze niż użycie SecurityIdentifier.Translate(). Pracuję w środowisku wielu lasów/domen z 60 tys. Użytkowników. –

0

Ten jest stumper. Jesteś w środowisku Active Directory, prawda? Tylko sprawdzam :)

Tak czy inaczej, zamiast wiązania z sid.Value,

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

Chciałbym spróbować konwersji bajt tablicę SID jest do Octet String i wiążą się z tym, że zamiast.

Istnieje słodki przykład here na stronie 78. To zbliży Cię do siebie. Szczerze mówiąc, wcześniej nie próbowałem wiązać się z identyfikatorem SID. Ale udało mi się powiązać z GUID użytkownika :)

Powodzenia i daj mi znać, jak to działa.

1

Ooh, to możliwe, że wywołanie LDAP nie działa, ponieważ może nie być w środowisku Active Directory. W takim przypadku każda z Twoich maszyn odpowiada za własny magazyn tożsamości. Twój pierwszy przykład kodu nie działa w sieci, ponieważ komputer, na którym uruchamiasz swój kod, nie wie, jak rozwiązać problem z identyfikatorem SID, który ma sens tylko na zdalnym komputerze.

Naprawdę powinieneś sprawdzić, czy twoje maszyny są częścią Active Directory. Wiedziałbyś o tym podczas procesu logowania. Możesz też sprawdzić, klikając prawym przyciskiem myszy "Mój komputer", wybierz "Właściwości", kartę "Nazwa komputera", a następnie sprawdź, czy Twój komputer jest częścią domeny.

-2

Jestem pewien, będziesz mógł korzystać z przyjętą odpowiedzi stąd: Determine the LocalSystem account name using C#

Zasadniczo można tłumaczyć instancją klasy Security Identifier wpisać NTaccount, z którego można uzyskać nazwę użytkownika. W kodzie:

using System.Security.Principal; 

SecurityIdentifier sid = new SecurityIdentifier("S-1-5-18"); 
NTAccount acct = (NTAccount)sid.Translate(typeof(NTAccount)); 
Console.WriteLine(acct.Value); 
+3

Chociaż nie jest to niepoprawne, to po prostu powtarza kod, który plakat już wskazał, nie działa w jego sytuacji. –

1

Świetnie. I żłobienia trochę LookupAccountSid() kod tutaj:

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

I to działało, chociaż musiałem dostarczyć gospodarz nazwać siebie. W przypadku ścieżki UNC mogę po prostu wziąć pierwszy składnik. Kiedy to jest zmapowany dysk, używam tego kodu, aby przekonwertować ścieżkę UNC jednym:

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

Wydaje się do pracy, więc to jak ja to zrobię, chyba że ktoś wyjdzie z sytuacją w którego pierwszym elementem ścieżki UNC nie jest nazwa hosta ...

Dziękuję wszystkim za pomoc.

37

Zobacz tutaj dobrej odpowiedzi:

The best way to resolve display username by SID?

Istotą niej jest ten bit:

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(); 

To podejście działa dla mnie non-local SID skończona aktywnego katalogu.

+1

To podejście zadziałało dla mnie tak jak jest. –

+1

Dzięki, pomogło mi to uzyskać nazwę użytkownika z zaufanej domeny. –

0

Pobierz aktualny domenę:

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

uzyskać wpis w katalogu z LDAP i nazwę swojej domeny:

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

uzyskać sid z ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

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

Get nazwa użytkownika z SecurityIdentifier:

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

katalogu Get wyszukiwanie odbywa się na ActiveDirectory z wejściem katalogu domeny i nazwę użytkownika:

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/>"; 
       } 
      } 
     } 

zależności od danych w aktywnym katalogu, dostaniesz zróżnicowane odpowiedzi na wyjściu.

Here is a site that has all the user properties I needed:

5

System.DirectoryServices.AccountManagement.UserPrincipal klasa (msdn link) ma statyczną funkcję FindByIdentity aby przekonwertować SID do obiektu użytkownika. Powinien działać zarówno na komputerze lokalnym, jak i na serwerze LDAP/Active Directory. Używałem go tylko przeciwko aktywnemu katalogowi.

Oto przykład, że użyłem w 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. 
+1

To jest właściwy sposób na zapytanie do obcych domen. P/Invoke nie jest wymagany. –

1

Można również uzyskać nazwę konta z rachunków specjalnych, takich jak „każdy” z kodem jak ten, który będzie działał niezależnie od ustawień językowych użytkownika:

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

Właśnie uratowałeś mi życie! – lukiller

1

W języku C#, dostać użytkownikowi Sid i przypisać ją do zmiennej łańcuchowej poprzez:

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

Będziesz musiał użyć ciągu znaków, ponieważ zdolność do rozpoznawania nazwy użytkownika obsługuje ciąg znaków. Innymi słowy, użycie var varUser spowoduje błąd przestrzeni nazw.

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