【问题标题】:When using ASP.NET how do you impersonate Windows Credentials?使用 ASP.NET 时如何模拟 Windows 凭据?
【发布时间】:2014-02-19 14:11:30
【问题描述】:

我创建了使用 IWA 的 asp.net (vb.net) 网站。完全没有问题。

但是现在我的用户不一定是我公司域的一部分,但登录到我的网络以访问公共信息。

我在我的 AD 上创建了一个公共帐户。我想做的是,当外部用户登录时,能够传递公共帐户凭据,以便他们可以访问公共信息。

这可能吗?

【问题讨论】:

    标签: asp.net vb.net


    【解决方案1】:

    您可以使用 web.config 中的身份模拟设置来设置凭据:

    <system.web>
      <authentication mode="Windows"/>
      <identity impersonate="true" userName="foo" password="bar"/>
    </system.web>
    

    您还应该加密 web.config,这样密码就不会以明文形式存储。 http://msdn.microsoft.com/en-us/library/89211k9b.aspx

    另一种选择是让您的用户能够在代码中冒充您的服务帐户。请注意,这段代码是用 C# 编写的,但我写它是为了即时模拟 Windows。它可以编译为 DLL 并在 VB.NET 中引用:

    /// <summary>
    /// Facilitates impersonation of a Windows User.
    /// </summary>
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    public class Impersonation : IDisposable
    {
        public string Environment { get; set; }
    
        public string UserName { get; set; }
    
        public string Password { get; set; }
    
        public string DomainName { get; set; }
    
        public enum LogonType
        {
            Interactive = 2,
            Network = 3,
            Batch = 4,
            Service = 5,
            Unlock = 7,
            NetworkClearText = 8,
            NewCredentials = 9
        }
    
        public enum LogonProvider
        {
            Default = 0,
            WinNT35 = 1,
            WinNT40 = 2,
            WinNT50 = 3
        }
    
        /// <summary>
        /// Windows Token.
        /// </summary>
        private readonly SafeTokenHandle _handle;
    
        /// <summary>
        /// The impersonated User.
        /// </summary>
        private WindowsImpersonationContext impersonatedUser;
    
        public Impersonation()
        {
        }
    
        /// <summary>
        /// Initializes a new instance of the Impersonation class. Provides domain, user name, and password for impersonation.
        /// </summary>
        /// <param name="domainName">Domain name of the impersonated user.</param>
        /// <param name="userName">Name of the impersonated user.</param>
        /// <param name="password">Password of the impersonated user.</param>
        /// <remarks>
        /// Uses the unmanaged LogonUser function to get the user token for
        /// the specified user, domain, and password.
        /// </remarks>
        public Impersonation(AccountCredentials credentials)
        {            
            string[] splitName = WindowsIdentity.GetCurrent().Name.Split('\\');
            string name = (splitName.Length > 0) ? splitName[0] : null;
    
            LogonType logonType = LogonType.Interactive;
            LogonProvider logonProvider = LogonProvider.Default;
    
            if (name != credentials.Domain)
            {
                logonType = LogonType.NewCredentials;
                logonProvider = LogonProvider.WinNT50;
            }
    
            // Call LogonUser to obtain a handle to an access token.
            bool returnValue = LogonUser(
                                credentials.UserName,
                                credentials.Domain,
                                credentials.Password,
                                (int)logonType,
                                (int)logonProvider,
                                out this._handle);
    
            if (!returnValue)
            {
                // Something went wrong.
                int ret = Marshal.GetLastWin32Error();
                throw new System.ComponentModel.Win32Exception(ret);
            }
    
            this.impersonatedUser = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());    
        }
    
        /// <summary>
        /// Initializes a new instance of the Impersonation class. Provide domain, user name, and password for impersonation.
        /// </summary>
        /// <param name="domainName">Domain name of the impersonated user.</param>
        /// <param name="userName">Name of the impersonated user.</param>
        /// <param name="password">Password of the impersonated user.</param>
        /// <remarks>
        /// Uses the unmanaged LogonUser function to get the user token for
        /// the specified user, domain, and password.
        /// </remarks>
        public Impersonation(string domainName, string userName, string password)
        {
            string[] splitName = WindowsIdentity.GetCurrent().Name.Split('\\');
            string name = (splitName.Length > 0) ? splitName[0] : null;
    
            LogonType logonType = LogonType.Interactive;
            LogonProvider logonProvider = LogonProvider.Default;
    
            if (name != domainName)
            {
                logonType = LogonType.NewCredentials;
                logonProvider = LogonProvider.WinNT50;
            }
    
            // Call LogonUser to obtain a handle to an access token.
            bool returnValue = LogonUser(
                                userName,
                                domainName,
                                password,
                                (int)logonType,
                                (int)logonProvider,
                                out this._handle);
    
            if (!returnValue)
            {
                    // Something went wrong.
                int ret = Marshal.GetLastWin32Error();
                throw new System.ComponentModel.Win32Exception(ret);
            }
    
            this.impersonatedUser = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());
        }
    
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool LogonUser(
                string lpszUsername,
                string lpszDomain,
                string lpszPassword,
                int dwLogonType,
                int dwLogonProvider,
                out SafeTokenHandle phToken);
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(IntPtr handle);
    
        public void Dispose()
        {
            this.impersonatedUser.Dispose();
            this._handle.Dispose();
        }
    
        private static string[] GetAccountInfo(string accountInfo)
        {
            return accountInfo.Split(' ');
        }
    }
    
    public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle()
            : base(true) { }
    
        [DllImport("kernel32.dll")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);
    
        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    }
    
    public class AccountCredentials
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        public string Domain { get; set; }
    }
    

    然后您将在 using 块中执行您的模拟操作:

    using(new Impersonation(new AccountCredentials("user", "password", "domain"))
    {
        // do impersonated actions
    }
    

    你需要在你的类中有这些 using 指令:

    using System;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Security.Principal;
    using Microsoft.Win32.SafeHandles;
    using System.Runtime.ConstrainedExecution;
    using System.Security;
    using System.Configuration;
    

    【讨论】:

    • 这将使他的所有用户都假定此 Windows 凭据不是他所需要的。他正在研究某种混合模式身份验证,其中网络内的用户使用他们的凭据,但外部用户应该使用所有相同的帐户。
    • 我已经添加了用于动态模拟的代码。它是用 C# 编写的,但可以在 VB.NET 中作为 DLL 引用。
    【解决方案2】:

    您可以临时冒充用户:

    在 c# 中,但您可以轻松将其转换为 vb

        if (!HttpContext.Current.User.Identity.IsAuthenticated) 
        {
           if (LogonUser("TempUser", Environment.MachineName, 
                      "password", LOGON32_LOGON_INTERACTIVE,
                      LOGON32_PROVIDER_DEFAULT, ref token) != 0)
           {
              if (DuplicateToken(token, SecurityImpersonation, ref tokenDuplicate) != 0)
              {
                m_ImpersonatedUser = new WindowsIdentity(tokenDuplicate);
                m_ImpersonationContext = m_ImpersonatedUser.Impersonate();                                
                try
                {
                    // impersonated code here       
                }        
                catch { throw; }
                finally
                {
                  m_ImpersonationContext.Undo();
                }
              }
           }
        }
    

    【讨论】:

      【解决方案3】:

      感谢大家提供的信息丰富的答案......抱歉这么晚才回来......所以我现在所做的是......

      导入 System.Web.Security

      导入 System.Security.Principal

      导入 System.Security.Permissions

      导入 System.Runtime.InteropServices

      导入 System.Environment

      公共类重定向 继承 System.Web.UI.Page

      Dim LOGON32_LOGON_INTERACTIVE As Integer = 2
      Dim LOGON32_PROVIDER_DEFAULT As Integer = 0
      
      Dim impersonationContext As WindowsImpersonationContext
      
      Declare Function LogonUserA Lib "advapi32.dll" (ByVal lpszUsername As String, _
                              ByVal lpszDomain As String, _
                              ByVal lpszPassword As String, _
                              ByVal dwLogonType As Integer, _
                              ByVal dwLogonProvider As Integer, _
                              ByRef phToken As IntPtr) As Integer
      
      Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _
                              ByVal ExistingTokenHandle As IntPtr, _
                              ByVal ImpersonationLevel As Integer, _
                              ByRef DuplicateTokenHandle As IntPtr) As Integer
      
      Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
      Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long
      
      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
          Dim redirstr As Integer
          redirstr = Request.QueryString("id")
          If impersonateValidUser("*username*", "*Domain*", "*Password*") Then
              'Insert your code that runs under the security context of a specific user here.
      
              Try
                  'Integrated Windows Authentication Site
                  Response.Redirect("http://<<servername>>/<app>/<<file>")
      
              Catch ex As Exception
      
              End Try
              undoImpersonation()
          Else
              'Your impersonation failed. Therefore, include a fail-safe mechanism here.
          'Not Integrated Windows Authentication Site
              Response.Redirect("http://<<servername>>:81/<app>/<<file>?user=<<username>>&pass=<<password>>)
          End If
      
      End Sub
      
      Private Function impersonateValidUser(ByVal userName As String, _
      ByVal domain As String, ByVal password As String) As Boolean
      
          Dim tempWindowsIdentity As WindowsIdentity
          Dim token As IntPtr = IntPtr.Zero
          Dim tokenDuplicate As IntPtr = IntPtr.Zero
          impersonateValidUser = False
      
          If RevertToSelf() Then
              If LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                           LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
                  If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
                      tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
                      impersonationContext = tempWindowsIdentity.Impersonate()
                      If Not impersonationContext Is Nothing Then
                          impersonateValidUser = True
                      End If
                  End If
              End If
          End If
          If Not tokenDuplicate.Equals(IntPtr.Zero) Then
              CloseHandle(tokenDuplicate)
          End If
          If Not token.Equals(IntPtr.Zero) Then
              CloseHandle(token)
          End If
      End Function
      
      Private Sub undoImpersonation()
          impersonationContext.Undo()
      End Sub
      

      结束类

      因此,在这种情况下,如果我的身份验证通过,理想情况下它应该将操作传递给 IWA 站点。它确实如此,但是一旦我进入 IWA 站点,它就会使用我的 Windows 凭据,而不是我试图模仿的那个。我如何做到这一点......使用我的模拟 Windows 用户凭据可以去哪里访问该站点?

      【讨论】:

        猜你喜欢
        • 2010-11-23
        • 2011-02-18
        • 2012-02-22
        • 1970-01-01
        • 2016-12-17
        • 1970-01-01
        • 2015-10-19
        • 1970-01-01
        • 2011-01-05
        相关资源
        最近更新 更多