2010-05-11 2 views

ответ

13

Это класс-оболочка мы создали, который работал на нескольких различных платформах Windows:

public class Impersonator 
{ 
    // constants from winbase.h 
    public const int LOGON32_LOGON_INTERACTIVE = 2; 
    public const int LOGON32_LOGON_NETWORK = 3; 
    public const int LOGON32_LOGON_BATCH = 4; 
    public const int LOGON32_LOGON_SERVICE = 5; 
    public const int LOGON32_LOGON_UNLOCK = 7; 
    public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8; 
    public const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 

    public const int LOGON32_PROVIDER_DEFAULT = 0; 
    public const int LOGON32_PROVIDER_WINNT35 = 1; 
    public const int LOGON32_PROVIDER_WINNT40 = 2; 
    public const int LOGON32_PROVIDER_WINNT50 = 3; 

    [DllImport("advapi32.dll", SetLastError=true)] 
    public static extern int LogonUserA(String lpszUserName, 
     String lpszDomain, 
     String lpszPassword, 
     int dwLogonType, 
     int dwLogonProvider, 
     ref IntPtr phToken); 
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
    public static extern int DuplicateToken(IntPtr hToken, 
     int impersonationLevel, 
     ref IntPtr hNewToken); 

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
    public static extern bool RevertToSelf(); 

    [DllImport("kernel32.dll", CharSet=CharSet.Auto)] 
    public static extern bool CloseHandle(IntPtr handle); 

    public static WindowsImpersonationContext LogOn(string userName, string password) 
    { 
     return LogOn(userName, password, ""); 
    } 

    public static WindowsImpersonationContext LogOn(string userName, string password, string domain) 
    { 
     WindowsIdentity tempWindowsIdentity; 
     WindowsImpersonationContext impersonationContext; 
     IntPtr token = IntPtr.Zero; 
     IntPtr tokenDuplicate = IntPtr.Zero; 

     if(RevertToSelf()) 
     { 
      if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, 
       LOGON32_PROVIDER_DEFAULT, ref token) != 0) 
      { 
       if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
       { 
        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
        impersonationContext = tempWindowsIdentity.Impersonate(); 
        if (impersonationContext != null) 
        { 
         CloseHandle(token); 
         CloseHandle(tokenDuplicate); 
         return impersonationContext; 
        } 
       } 
      } 
      else 
      { 
       var win32 = new Win32Exception(Marshal.GetLastWin32Error()); 
       //throw new Exception(string.Format("{0}, Domain:{1}, User:{2}, Password:{3}", 
       // win32.Message, domain, userName, password)); 
       throw new Exception(win32.Message); 
      } 
     } 
     if(token!= IntPtr.Zero) 
      CloseHandle(token); 
     if(tokenDuplicate!=IntPtr.Zero) 
      CloseHandle(tokenDuplicate); 
     return null; // Failed to impersonate 
    } 

    public static bool LogOff(WindowsImpersonationContext context) 
    { 
     bool result = false; 
     try 
     { 
      if (context != null) 
      { 
       context.Undo(); 
       result = true; 
      } 
     } 
     catch 
     { 
      result = false; 
     } 
     return result; 
    } 
} 
+0

отлично поработал John. Спасибо. – GR7

+0

Добро пожаловать, silverCORE –

+0

Где вы находите значения LOGON32_PROVIDER_x? –

1

Там в аналогичный вопрос с большим ответом here.

Посмотрите WindowsImpersonationContext для более определенной информации (также есть еще один отличный пример кода там)

+0

было интересно, если бы это можно было сделать без каких-либо dllimports – Simon

+2

Если это веб-сайт ASP.NET, то да, это можно сделать, установив элемент '' в 'web .config'. В противном случае вам придется использовать импорт :( – Codesleuth

+0

@Simon: олицетворение также полезно во время установки или для запуска приложения «как» кто-то другой, например, администратор. – AMissico

0

См ImpersonationHelper из Is it possible to safely get a SecureString value from VB .NET?. Код является готовым к производству и надежным.

Он поддерживает IDisposable, содержит метод RunAs (что бесценно), пароли обрабатываются как SecureString и другие полезные полезные свойства. Я также предоставил код для тестирования как для класса ImpersonationHelper, так и для устранения неполадок, и их методы SecureString extenstion, которые пригождаются.

2

Я варил до двух простых методов:

public bool ImpersonateValidUser(String userName, String domain, String password) 
public void UndoImpersonation() 

Вы можете directlyh копировать/вставить класс ниже, и использовать его в вашем проекте:

class ImpersonationContext 
    { 
     [DllImport("advapi32.dll")] 
     public static extern int LogonUserA(String lpszUserName, 
      String lpszDomain, 
      String lpszPassword, 
      int dwLogonType, 
      int dwLogonProvider, 
      ref IntPtr phToken); 
     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern int DuplicateToken(IntPtr hToken, 
      int impersonationLevel, 
      ref IntPtr hNewToken); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern bool RevertToSelf(); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
     public static extern bool CloseHandle(IntPtr handle); 

     public const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 
     public const int LOGON32_LOGON_INTERACTIVE = 2; 
     public const int LOGON32_PROVIDER_DEFAULT = 0; 
     public const int LOGON32_PROVIDER_WINNT50 = 3; 
     WindowsImpersonationContext impersonationContext; 

     public bool ImpersonateValidUser(String userName, String domain, String password) 
     { 
      WindowsIdentity tempWindowsIdentity; 
      IntPtr token = IntPtr.Zero; 
      IntPtr tokenDuplicate = IntPtr.Zero; 

      if (RevertToSelf()) 
      { 
       if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, 
        LOGON32_PROVIDER_WINNT50, ref token) != 0) 
       { 
        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
        { 
         tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
         impersonationContext = tempWindowsIdentity.Impersonate(); 
         if (impersonationContext != null) 
         { 
          CloseHandle(token); 
          CloseHandle(tokenDuplicate); 
          return true; 
         } 
        } 
       } 
      } 
      if (token != IntPtr.Zero) 
       CloseHandle(token); 
      if (tokenDuplicate != IntPtr.Zero) 
       CloseHandle(tokenDuplicate); 
      return false; 
     } 

     public void UndoImpersonation() 
     { 
      impersonationContext.Undo(); 
     } 
    } 
+0

Конечно, это сводится к двум методам. не имеет обработки ошибок, и если ошибка не возникает, не освобождает созданные ею дескрипторы. – AMissico

2

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

Например, это будет работать только в том случае, если пользователь, у которого вы выдаете себя за прав, имеет разрешение на вход в целевую систему. Не всегда при доступе к удаленному ящику SQL Server. LOGON32_LOGON_INTERACTIVE

NetworkClearText является единственным, который работает последовательно для использования с соединениями SQL Server. - Нет четкого текста, это не означает, что он передаёт учетные данные небезопасным образом.

Когда на рабочей группе и вы должны олицетворять пользователя домена, NewCredentials - это тот, который работает. (не тестировалось с подключением SQL Server)

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