2010-05-04 2 views
4

КонтекстПоиск Windows Пользователи УЛМ в C#

Контекст первый - вопросы, которые я пытаюсь решить ниже.

[EDIT] Приложение в вопросах построено на .NET 3.5 SP1.

Один из наших клиентов попросил указать, сколько времени потребуется, чтобы улучшить одно из наших приложений. В настоящее время это приложение обеспечивает базовую аутентификацию пользователя в виде комбинаций имени пользователя и пароля. Этот клиент хотел бы, чтобы их сотрудники могли входить в систему, используя сведения о том, какая учетная запись Windows была зарегистрирована на момент запуска приложения.

Это не сделка, если я говорю им нет, но клиент может согласиться заплатить затраты на разработку, чтобы добавить эту функцию в приложение. Это стоит посмотреть.

Основываясь на моей охоте вокруг, похоже, что сохранение данных входа пользователя в домен с домена \ Имя пользователя будет проблематичным, если эти детали будут изменены. Но SID Windows User не должны вообще меняться. У меня сложилось впечатление, что лучше всего записывать пользователей Windows по SID - не стесняйтесь меня освобождать, если я ошибаюсь.

У меня была скрипка с некоторыми вызовами Windows API. Изнутри C# захват SID текущего пользователя достаточно прост. Я уже могу использовать SID любого пользователя и обрабатывать его с помощью LookupAccountSid, чтобы получить имя пользователя и домен для отображения. Для заинтересованного, мой код для этого находится в конце этого сообщения.

Это только верхушка айсберга. Эти два вопроса ниже полностью вне моего опыта. Я не только не знаю, как их реализовать - я даже не знаю, как узнать, как их реализовать, или какие подводные камни находятся в разных системах.

Любая помощь, направленная на правильное направление, будет очень признательна.

Выпуск 1)

Получение трюм локального пользователя во время выполнения не имеет смысла, если пользователь не был предоставлен доступ к приложению. Нам нужно будет добавить новый раздел в консоль администратора для добавления пользователей Windows (или групп) и назначения разрешений внутри приложения для этих пользователей.

Что-то вроде кнопки «Добавить пользователя Windows», которая приведет к появлению всплывающего окна, которое позволит пользователю искать доступные учетные записи пользователей Windows в сети (а не только локальную машину), которая будет добавлена ​​к список доступных логинов приложений.

Если в .NET или Windows уже есть компонент, в котором я могу сделать это для меня, это сделает меня очень счастливым человеком.

Выпуск 2)

Я также хочу знать, как принять данную пользователей Windows SID и проверьте его с данной ОС Windows User Group (вероятно, взяты из базы данных). Я не уверен, как начать работу с этим, хотя я ожидаю, что это будет проще, чем проблема выше.

Для Заинтересованной

[STAThread] 
static void Main(string[] args) 
{ 
    MessageBox.Show(WindowsUserManager.GetAccountNameFromSID(WindowsIdentity.GetCurrent().User.Value)); 
    MessageBox.Show(WindowsUserManager.GetAccountNameFromSID("S-1-5-21-57989841-842925246-1957994488-1003")); 
} 

public static class WindowsUserManager 
{ 
    public static string GetAccountNameFromSID(string SID) 
    { 
     try 
     { 
      StringBuilder name = new StringBuilder(); 
      uint cchName = (uint)name.Capacity; 
      StringBuilder referencedDomainName = new StringBuilder(); 
      uint cchReferencedDomainName = (uint)referencedDomainName.Capacity; 
      WindowsUserManager.SID_NAME_USE sidUse; 

      int err = (int)ESystemError.ERROR_SUCCESS; 
      if (!WindowsUserManager.LookupAccountSid(null, SID, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sidUse)) 
      { 
       err = Marshal.GetLastWin32Error(); 
       if (err == (int)ESystemError.ERROR_INSUFFICIENT_BUFFER) 
       { 
        name.EnsureCapacity((int)cchName); 
        referencedDomainName.EnsureCapacity((int)cchReferencedDomainName); 

        err = WindowsUserManager.LookupAccountSid(null, SID, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sidUse) ? 
         (int)ESystemError.ERROR_SUCCESS : 
         Marshal.GetLastWin32Error(); 
       } 
      } 

      if (err != (int)ESystemError.ERROR_SUCCESS) 
       throw new ApplicationException(String.Format("Could not retrieve acount name from SID. {0}", SystemExceptionManager.GetDescription(err))); 

      return String.Format(@"{0}\{1}", referencedDomainName.ToString(), name.ToString()); 
     } 
     catch (Exception ex) 
     { 
      if (ex is ApplicationException) 
       throw ex; 

      throw new ApplicationException("Could not retrieve acount name from SID", ex); 
     } 
    } 

    private enum SID_NAME_USE 
    { 
     SidTypeUser = 1, 
     SidTypeGroup, 
     SidTypeDomain, 
     SidTypeAlias, 
     SidTypeWellKnownGroup, 
     SidTypeDeletedAccount, 
     SidTypeInvalid, 
     SidTypeUnknown, 
     SidTypeComputer 
    } 

    [DllImport("advapi32.dll", EntryPoint = "GetLengthSid", CharSet = CharSet.Auto)] 
    private static extern int GetLengthSid(IntPtr pSID); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern bool ConvertStringSidToSid(
       string StringSid, 
       out IntPtr ptrSid); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern bool LookupAccountSid(
     string lpSystemName, 
     [MarshalAs(UnmanagedType.LPArray)] byte[] Sid, 
     StringBuilder lpName, 
     ref uint cchName, 
     StringBuilder ReferencedDomainName, 
     ref uint cchReferencedDomainName, 
     out SID_NAME_USE peUse); 

    private static bool LookupAccountSid(
     string lpSystemName, 
     string stringSid, 
     StringBuilder lpName, 
     ref uint cchName, 
     StringBuilder ReferencedDomainName, 
     ref uint cchReferencedDomainName, 
     out SID_NAME_USE peUse) 
    { 
     byte[] SID = null; 
     IntPtr SID_ptr = IntPtr.Zero; 
     try 
     { 
      WindowsUserManager.ConvertStringSidToSid(stringSid, out SID_ptr); 

      int err = SID_ptr == IntPtr.Zero ? Marshal.GetLastWin32Error() : (int)ESystemError.ERROR_SUCCESS; 

      if (SID_ptr == IntPtr.Zero || 
       err != (int)ESystemError.ERROR_SUCCESS) 
       throw new ApplicationException(String.Format("'{0}' could not be converted to a SID byte array. {1}", stringSid, SystemExceptionManager.GetDescription(err))); 

      int size = (int)GetLengthSid(SID_ptr); 
      SID = new byte[size]; 

      Marshal.Copy(SID_ptr, SID, 0, size); 
     } 
     catch (Exception ex) 
     { 
      if (ex is ApplicationException) 
       throw ex; 

      throw new ApplicationException(String.Format("'{0}' could not be converted to a SID byte array. {1}.", stringSid, ex.Message), ex); 
     } 
     finally 
     { 
      // Always want to release the SID_ptr (if it exists) to avoid memory leaks. 
      if (SID_ptr != IntPtr.Zero) 
       Marshal.FreeHGlobal(SID_ptr); 
     } 

     return WindowsUserManager.LookupAccountSid(lpSystemName, SID, lpName, ref cchName, ReferencedDomainName, ref cchReferencedDomainName, out peUse); 
    } 
} 

ответ

3

Если вы используете версию Framework 3.5, вы действительно посмотреть в System.DirectoryServices.AccountManagement. Я использовал его раньше, чтобы обеспечить поиск учетных записей AD, и это гораздо проще, чем писать собственный класс. Он также решит ваш вопрос №2. У меня нет кода под рукой, но если вам это нужно, я всегда могу найти его.

+0

+1 Встроенная библиотека .NET всегда должна быть рассмотрена до того, как вы начнете свой собственный. – Sekhat

+0

Да, мы используем 3.5 - отредактировали главный пост, чтобы отразить это. Спасибо за пространство имен, я проведу расследование и вернусь позже. –

 Смежные вопросы

  • Нет связанных вопросов^_^