11

这是我一直在尝试做的

使用表单身份验证和活动目录成员身份构建 ASP.NET MVC 3 应用程序。Web 服务器和数据库是不同的物理服务器,因此是双跳。

我认为答案是这篇关于约束委派和协议转换的旧文章?到目前为止,我还不能让这项技术发挥作用。

在部署到生产设置中的 Windows 2008 (IIS7) 之前,我正在从我的 DEV 机器(Windows 7、IIS7)上测试这个 Web 服务器。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();
                }
            }
        }
    }

它失败并出现异常,导致我相信我在本地 DEV 服务器上存在设置问题。内部例外是Requested registry access is not allowed.

如果我设置断点并WindowsIdentity在调用后检查,Impersonate()我会看到ImpersonationLevel设置为Identification. 这似乎是它设置不正确的线索。任何人都可以确认吗?

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

4

5 回答 5

5

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

我假设您正确配置了 Active Directory 成员资格提供程序,以便您可以使用 Active Directory 用户名和密码成功登录您的网页。如果不是这样,请忽略我的其余答案:)

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

您需要了解允许一台机器在域中进行协议转换是非常高的特权。授予服务器进行协议转换几乎意味着您相信该服务器几乎就像一个域控制器。您需要有意识地在 AD 中做出此决定以使服务器具有此功能,并且您必须是域管理员才能进行此更改。如果你还没有这样做,你可能没有正确设置你的东西。

有几件事要检查。

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

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

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

更新

我刚刚发现另一篇文章教你如何设置 ASP.NET 的协议转换。它提到您需要向 IIS 服务帐户授予 TCB 权限,以确保它可以创建Impersonation类型 WindowsIdentity。你可以试一试。

于 2011-02-22T07:06:31.343 回答
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
    }
于 2011-02-21T21:59:46.233 回答
1

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

于 2011-02-21T19:31:47.013 回答
1

您还应该与您的 AD 管理人员核实是否允许模拟。我公司的广告政策不允许冒充。

于 2011-02-21T19:49:07.657 回答
1

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

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

这不会发生在匿名访问或模拟关闭的情况下,因为在这种情况下,IIS 会负责对您进行身份验证,然后使用不同的用户进行本地或网络访问。这意味着应用程序池身份或匿名用户可以将网络调用作为第一跳。

我认为很明显,除了第一次连接之外,您无法传递您的凭据。

于 2011-02-22T17:57:01.483 回答