Как я могу конвертировать из SID в имя учетной записи в С#

У меня есть приложение С#, которое сканирует каталог и собирает некоторую информацию. Я хотел бы отобразить имя учетной записи для каждого файла. Я могу сделать это в локальной системе, получив 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, который, возможно, я должен использовать, но он хочет имя домена, и я не знаю, как это получить - все, что у меня есть, - путь к каталогу, который я просматриваю.

Спасибо заранее.

Ответ 1

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

Ответ 2

См. здесь хороший ответ:

Лучший способ разрешить отображение имени пользователя по 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();

Этот подход работает для меня для нелокального SID в активном каталоге.

Ответ 3

Класс System.DirectoryServices.AccountManagement.UserPrincipal (ссылка FindByIdentity) имеет статическую функцию 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.

Ответ 4

В С# получить 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();

Ответ 5

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

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

Ответ 6

Великий. Я скрепил код LookupAccountSid() отсюда:

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

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

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

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

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

Ответ 7

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

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

Ответ 8

Это один из них. Вы находитесь в среде Active Directory правильно? Просто проверьте:)

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

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

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

Ниже представлен приятный пример здесь на странице 78. Это приблизит вас. Честно говоря, я раньше не пытался связываться с SID. Но у меня была успешная привязка к GUID пользователя, хотя:)

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

Ответ 9

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

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

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

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

Ответ 10

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

В принципе, вы можете перевести экземпляр класса 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);