【问题标题】:LogonUser and delegationLogonUser 和委派
【发布时间】:2010-11-03 01:03:16
【问题描述】:

我正在使用 LogonUser win32 api:

token = LogonUser(...)
WindowsIdentity newId = new WindowsIdentity(token);            
WindowsImpersonationContext impersonatedUser = newId.Impersonate();

但是,在此之后调用 WCF 服务时,我无法使用模拟身份。我认为这是因为 impersonatedUser.ImpersonationLevel 等于 Impersonation。

是这个原因吗? ImpersonationLevel.Identification 级别是我需要的吗? 怎么达到这样的水平?

【问题讨论】:

    标签: c# winapi impersonation delegation


    【解决方案1】:

    我不知道这是否适用于 WCF。但是我们在我们的生产网络应用程序中使用它来模拟读取和写入文件到文件系统。您需要为 AdvApi32.LogonUser、AdvApi32.DuplicateToken 和 Kernel32.CloseHandle 定义 API,并确保在完成后关闭 WindowsImpersonationContext。

        /// <summary>impersonates a user</summary>
        /// <param name="username">domain\name of the user account</param>
        /// <param name="password">the user's password</param>
        /// <returns>the new WindowsImpersonationContext</returns>
        public static WindowsImpersonationContext ImpersonateUser(String username, String password)
        {
            WindowsIdentity winId = WindowsIdentity.GetCurrent();
            if (winId != null)
            {
                if (string.Compare(winId.Name, username, true) == 0)
                {
                    return null;
                }
            }
    
            //define the handles
            IntPtr existingTokenHandle = IntPtr.Zero;
            IntPtr duplicateTokenHandle = IntPtr.Zero;
    
            String domain;
            if (username.IndexOf("\\") > 0)
            {
                //split domain and name
                String[] splitUserName = username.Split('\\');
                domain = splitUserName[0];
                username = splitUserName[1];
            }
            else
            {
                domain = String.Empty;
            }
    
            try
            {
                //get a security token
    
                bool isOkay = AdvApi32.LogonUser(username, domain, password,
                    (int) AdvApi32.LogonTypes.LOGON32_LOGON_INTERACTIVE,
                    (int) AdvApi32.LogonTypes.LOGON32_PROVIDER_DEFAULT,
                    ref existingTokenHandle);
    
                if (!isOkay)
                {
                    int lastWin32Error = Marshal.GetLastWin32Error();
                    int lastError = Kernel32.GetLastError();
    
                    throw new Exception("LogonUser Failed: " + lastWin32Error + " - " + lastError);
                }
    
                // copy the token
    
                isOkay = AdvApi32.DuplicateToken(existingTokenHandle,
                    (int) AdvApi32.SecurityImpersonationLevel.SecurityImpersonation,
                    ref duplicateTokenHandle);
    
                if (!isOkay)
                {
                    int lastWin32Error = Marshal.GetLastWin32Error();
                    int lastError = Kernel32.GetLastError();
                    Kernel32.CloseHandle(existingTokenHandle);
                    throw new Exception("DuplicateToken Failed: " + lastWin32Error + " - " + lastError);
                }
                // create an identity from the token
    
                WindowsIdentity newId = new WindowsIdentity(duplicateTokenHandle);
                WindowsImpersonationContext impersonatedUser = newId.Impersonate();
    
                return impersonatedUser;
            }
            finally
            {
                //free all handles
                if (existingTokenHandle != IntPtr.Zero)
                {
                    Kernel32.CloseHandle(existingTokenHandle);
                }
                if (duplicateTokenHandle != IntPtr.Zero)
                {
                    Kernel32.CloseHandle(duplicateTokenHandle);
                }
            }
        }
    

    【讨论】:

    • 对创建 WindowsIdentity 实例感兴趣的人请注意:WindowsIdentity.Dispose() 关闭其令牌句柄,这意味着如果您调用 Dispose,则不需要调用 CloseHandle(duplicateTokenHandle)
    • @Joh - 我不认为这是正确的。 Dispose 确实 调用CloseHandle(),但不在传递给构造函数的句柄上。构造函数复制提供的句柄;它是在Dispose 中关闭的副本。
    【解决方案2】:

    在此之后我无法使用 冒充身份

    模拟应该在同一个盒子上有效,而不是在网络上。

    正如consultutah 的代码所示,您可能只需要调用 DuplicateToken() 即可将登录令牌转换为模拟令牌,然后才能使用它。

    我认为这是因为 impersonatedUser.ImpersonationLevel 等于 Impersonation。

    如果您需要充当其他系统的模拟用户,则需要更高级别的模拟,称为“委托”。这基本上等同于拥有用户密码,这样您就可以向他人展示自己。

    【讨论】:

      猜你喜欢
      • 2015-02-08
      • 2010-12-02
      • 2016-04-30
      • 1970-01-01
      • 2010-12-14
      • 1970-01-01
      • 2013-01-11
      • 2013-12-05
      • 1970-01-01
      相关资源
      最近更新 更多