Как я могу конвертировать из SID в имя учетной записи в C # - PullRequest
51 голосов
/ 31 января 2009

У меня есть приложение на C #, которое сканирует каталог и собирает некоторую информацию. Я хотел бы отобразить имя учетной записи для каждого файла. Я могу сделать это в локальной системе, получив SID для объекта FileInfo, а затем выполнив:

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

Однако это не работает для файлов в сети, возможно потому, что функция Translate () работает только с локальными учетными записями пользователей. Я подумал, что, возможно, смогу выполнить поиск LDAP по SID, поэтому я попробовал следующее:

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

Кажется, что это будет работать, так как доступ к "dirEntry.Name" зависает на несколько секунд, как будто он отключается и запрашивает сеть, но затем выдает System.Runtime.InteropServices.COMException

Кто-нибудь знает, как я могу получить имя учетной записи произвольного файла или SID? Я не знаю много о сети или LDAP или что-то еще. Есть класс DirectorySearcher, который, возможно, я должен использовать, но он хочет доменное имя, и я тоже не знаю, как его получить - все, что у меня есть, - это путь к каталогу, который я сканирую.

Заранее спасибо.

Ответы [ 10 ]

38 голосов
/ 12 марта 2009

Смотри здесь для хорошего ответа:

Лучший способ разрешить отображение имени пользователя по SID?

Суть этого в следующем:

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

Этот подход работает у меня для нелокальных идентификаторов безопасности над активным каталогом.

17 голосов
/ 02 февраля 2009

Метод Translate объекта SecurityReference работает с нелокальными идентификаторами безопасности, но только для учетных записей домена. Для учетных записей, локальных для другого компьютера или не входящих в домен, вам нужно вызвать функцию LookupAccountSid, указав конкретное имя компьютера, на котором необходимо выполнить поиск.

5 голосов
/ 20 июля 2012

System.DirectoryServices.AccountManagement.UserPrincipal class ( msdn link ) имеет статическую функцию FindByIdentity для преобразования SID в объект User. Он должен работать как на локальном компьютере, так и на сервере LDAP / Active Directory. Я использовал его только против активной директории.

Вот пример, который я использовал в 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.
3 голосов
/ 19 февраля 2017

В C # получите SID пользователя и присвойте его строковой переменной с помощью:

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

Вам нужно будет использовать строку, потому что возможность преобразования в имя пользователя поддерживает строку. Другими словами, использование var varUser приведет к ошибке пространства имен.

string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString();
1 голос
/ 01 декабря 2015

Вы также можете получить имя учетной записи специальных учетных записей, таких как «Все», с кодом, подобным этому, который будет работать независимо от языковых настроек пользователя:

   SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
   string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();
1 голос
/ 02 февраля 2009

Отлично. Я набрал некоторый код LookupAccountSid () отсюда:

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

И это сработало, хотя я должен был сам указать имя хоста. В случае UNC-пути я могу взять только первый его компонент. Когда это подключенный диск, я использую этот код для преобразования пути в UNC-код:

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

Кажется, это работает, поэтому я так и сделаю, если кто-то не придет в ситуацию, когда первый компонент пути UNC не является именем хоста ...

Спасибо всем за помощь.

1 голос
/ 01 февраля 2009

Ох, тогда возможно, что вызов LDAP не работает, потому что вы можете не находиться в среде Active Directory. Если это так, то каждый из ваших компьютеров отвечает за свое собственное хранилище идентификаторов. И ваш первый пример кода не работает в сети, потому что компьютер, на котором вы выполняете код, не знает, как разрешить SID, который имеет смысл только на удаленном компьютере.

Вы действительно должны проверить, являются ли ваши машины частью Active Directory. Вы узнаете об этом во время входа в систему. Или вы можете проверить, щелкнув правой кнопкой мыши «Мой компьютер», выбрать «Свойства», вкладку «Имя компьютера», а затем посмотреть, является ли ваш компьютер частью домена.

0 голосов
/ 18 мая 2009

Получить текущий домен:

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

Получить запись каталога из ldap и имя домена:

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

Получить sid из ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

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

Получить имя пользователя от SecurityIdentifier:

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

Выполнение поиска в каталоге в активном каталоге с записью каталога домена и именем пользователя:

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

В зависимости от данных в вашем активном каталоге, вы получите различный ответ в выводе.

Вот сайт, на котором есть все необходимые мне свойства пользователя:

0 голосов
/ 01 февраля 2009

Я вполне уверен, что вы сможете использовать принятый ответ отсюда: Определите имя учетной записи LocalSystem, используя C #

По сути, вы можете перевести экземпляр класса SecurityIdentifier в тип NTAccount, из которого вы можете получить имя пользователя. В коде:

using System.Security.Principal;

SecurityIdentifier sid = new SecurityIdentifier("S-1-5-18");
NTAccount acct = (NTAccount)sid.Translate(typeof(NTAccount));
Console.WriteLine(acct.Value);
0 голосов
/ 31 января 2009

Это тупик. Вы находитесь в среде Active Directory, верно? Просто проверяю:)

Во всяком случае, вместо связывания с sid.Value,

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

Я бы попытался преобразовать байтовый массив SID в Octet String и связать его с этим.

Вот замечательный пример здесь на странице 78. Это приблизит вас. Если честно, я не пробовал связываться с SID раньше. Но я успешно связался с GUID пользователя :)

Удачи, и дайте мне знать, как это происходит.

...