11

这是我一直在努力做我可以模拟使用表单身份验证进行身份验证的客户端并建立到SQL Server的可信连接吗?

建立与窗体身份验证和Active Directory成员的ASP.NET MVC 3应用程序。 Web服务器和数据库是不同的物理服务器,因此是双跳。

我以为答案是constrained delegation and protocol transition上的这篇较旧的文章?到目前为止,我还没有能够获得这项技术的工作。

我正在测试这从我的DEV机器(Windows 7,IIS7)的Web服务器部署到生产设置中的Windows 2008(IIS7)之前。 Windows 2008会有所作为吗?

什么可行,什么失败

我能够与窗体身份验证和AD会员登录。这似乎工作正常。当我试图让使用此代码数据库调用:

public void AsUser(Action action) 
    { 
     using (var id = new WindowsIdentity(User.Identity.Name + @"@example.com")) 
     { 
      WindowsImpersonationContext context = null; 
      try 
      { 
       context = id.Impersonate(); 
       action.Invoke(); 
      } 
      catch (Exception ex) 
      { 
       // ex.Message is The type initializer for System.Data.SqlClient.SqlConnection threw an exception 
       // buried inner exeption is Requested registry access is not allowed 
      } 
      finally 
      { 
       if (context != null) 
       { 
        context.Undo(); 
       } 
      } 
     } 
    } 

它失败的异常导致我相信我有我的本地开发服务器上设置问题。内部例外是Requested registry access is not allowed

如果我的电话Impersonate()我看到ImpersonationLevel设置为Identification后设置一个断点,并检查WindowsIdentity。这似乎是一个线索,它没有正确设置。有人可以确认吗?

我在正确的轨道上,这甚至可以设置?任何指针,将不胜感激。

回答

5

我认为你是在正确的轨道上。您只需要在协议转换设置上进行更多的故障排除工作。

我假设您正确配置了您的Active Directory成员资格提供程序,以便您可以使用活动目录用户名和密码成功登录您的网页。如果情况并非如此,请忽略我的答案:)

从我在您的问题中看到的,您通过WindowsIdentity使用S4USelf获得了您的用户令牌。然后,您使用S4UProxy将模拟的令牌传递给SQL服务器。既然你说你只有ImpersonationLevel.Identification,这意味着你没有做协议转换。

您需要了解允许一台机器在域中执行协议转换的权限非常高。授予服务器执行协议转换几乎意味着您相信该服务器几乎就像域控制器一样。你需要在AD中有意识地做出这个决定来让服务器拥有这种能力,并且你必须成为一名domian管理员才能做出这样的改变。如果你没有这样做,你可能没有正确设置你的东西。

有几件事要检查。

首先,请确保您选择了“信任此计算机以委托指定的服务”,然后选择“选择使用任何身份验证协议”在您的服务帐户上。您可能想创建一个域帐户。 Here是关于如何为ASP.NET创建服务帐户的链接。请记住,您需要一个域帐户。创建域服务帐户后,请确保转到该帐户的委派选项卡并选择正确的选项。

其次,您需要确保SPNs设置正确。我知道您发布的链接仅提及您的ASP.NET服务帐户的SPN。实际上,您还需要确保您的SQL服务器上的服务帐户也正确设置。 Otheriwse,Windows根本不会使用Kerberos身份验证。它会回退到使用NTLM。有很多细节可以在SQL Server上正确设置SPN。你可以先检查here,看看你是否有幸运。根据我的经验,大多数DBA不知道如何正确设置它们。他们甚至没有意识到这一点,因为大多数应用程序在NTLM上运行良好。您需要注意SQL Server服务帐户及其使用的端口号。

第三,您需要确保没有任何功能禁用您的Kerberos委派。一些敏感的AD账户默认不允许被委派。例如,内置的管理员帐户。所以,你最好使用其他一些普通的用户帐户进行测试。

UPDATE

我刚刚发现another article教你如何设置用于ASP.NET的协议转换。它提到您需要授予TCB对IIS服务帐户的权利,以确保它可以创建类型为WindowsIdentity的Impersonation。你可以试试看。

1

您是否在Windows 7或Windows 2008计算机上启用了模拟?本文将介绍如何进行设置。 http://technet.microsoft.com/en-us/library/cc730708(WS.10).aspx。另外,你正在运行32位或64位?

+0

64位。这很重要吗? – 2011-02-21 22:14:56

+0

有时。在这种情况下,我怀疑它。更多信息总是更好,但 – Spidy 2011-02-21 22:17:11

1

您还应该向您的AD管理部门查询是否允许模仿。我的公司AD政策不允许冒充。

2

这里是我使用的类。此外,您需要检查AppPool正在运行的进程是否具有足够的权限来执行模拟,因为它是一项特权活动。我会给用户帐户,该应用程序池在临时管理权限下运行(当然只有开发框),看看它是否有效,以便知道它是否是权限问题。

public class ImpersonationHelper : IDisposable 
    { 
     private const int LOGON32_LOGON_INTERACTIVE = 2; 
     private const int LOGON32_PROVIDER_DEFAULT = 0; 
     private WindowsImpersonationContext _impersonationContext; 
     private string _userName; 
     private string _domain; 
     private string _password; 

     [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 ImpersonationHelper(string domain, string userName, string password) 
     { 
      _userName = userName; 
      _domain = domain; 
      _password = password; 
     } 

     public void Start() 
     { 
      WindowsIdentity tempWindowsIdentity; 
      IntPtr token = IntPtr.Zero; 
      IntPtr tokenDuplicate = IntPtr.Zero; 

      if (RevertToSelf()) 
      { 
       if (LogonUserA(_userName, _domain, _password, LOGON32_LOGON_INTERACTIVE, 
        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); 
         } 
        } 
       } 
      } 
      if (token != IntPtr.Zero) 
       CloseHandle(token); 
      if (tokenDuplicate != IntPtr.Zero) 
       CloseHandle(tokenDuplicate); 
     } 

     #region IDisposable Members 

     void IDisposable.Dispose() 
     { 
      if (_impersonationContext != null) 
      { 
       _impersonationContext.Undo(); 
      } 
     } 

     #endregion 
    } 
+0

感谢您的代码。我希望能够在没有外部呼叫的情况下留在快乐的管理区域,但如果谈到这一点,我会给它一个机会。 – 2011-02-23 13:32:52

1

我想你已经发现了这个问题,但没有人提到它。 “双跳”问题不会允许你这样做。这是不可能的。有很多人写过关于它的文章,例如Scott Forsyth

当您进行身份验证使用集成 身份验证的IIS服务器 ,使用你的 第一个“跳”。当IIS试图访问网络设备 时,这将是 双或第二跳,而不是 允许。 IIS不会将 这些凭据传递给下一个网络 设备,否则开发人员或 管理员可能会滥用您的凭证并以网站访问者未预料到的方式使用它们。

,因为在这种情况下,IIS需要的 照顾验证你,然后它使用本地或网络 访问 不同的用户这不会与匿名 访问或冒充关闭 发生。这意味着应用程序池 身份或匿名用户可以将网络呼叫作为第一跳。

我认为很明显,你不能通过你的凭证比第一个连接更远。

相关问题