Active directory 我是否可以模拟使用forms auth进行身份验证的客户端,并与SQL Server建立可信连接?

Active directory 我是否可以模拟使用forms auth进行身份验证的客户端,并与SQL Server建立可信连接?,active-directory,asp.net-mvc-3,forms-authentication,trustedconnection,Active Directory,Asp.net Mvc 3,Forms Authentication,Trustedconnection,以下是我一直在尝试做的事情 使用窗体身份验证和active directory成员身份构建ASP.NET MVC 3应用程序。web服务器和数据库是不同的物理服务器,因此是双跳 我还以为答案是这篇关于?到目前为止,我还没能让这项技术发挥作用 在生产设置中部署到Windows 2008(IIS7)之前,我正在为web服务器从我的开发机器(Windows 7,IIS7)进行测试。windows 2008会有所不同吗 什么有效,什么失败 我可以用forms auth和广告会员身份登录。这似乎很有效。当

以下是我一直在尝试做的事情

使用窗体身份验证和active directory成员身份构建ASP.NET MVC 3应用程序。web服务器和数据库是不同的物理服务器,因此是双跳

我还以为答案是这篇关于?到目前为止,我还没能让这项技术发挥作用

在生产设置中部署到Windows 2008(IIS7)之前,我正在为web服务器从我的开发机器(Windows 7,IIS7)进行测试。windows 2008会有所不同吗

什么有效,什么失败

我可以用forms auth和广告会员身份登录。这似乎很有效。当我尝试使用以下代码进行数据库调用时:

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();
                }
            }
        }
    }
它失败了,出现了一个异常,使我相信我的本地开发服务器上存在安装问题。内部异常是
不允许请求的注册表访问

如果在调用
Impersonate()
后设置断点并检查
windowsindential
,我会看到
ImpersonationLevel
设置为
Identification
。这似乎是一个线索,它没有正确设置。有人能证实吗


我是否在正确的轨道上,这是否可以设置?任何提示都将不胜感激。

您是否已在Windows 7或Windows 2008计算机上启用模拟功能?本文介绍如何设置它。另外,您运行的是32位还是64位?

您还应该与广告管理部门联系,查看是否允许模拟。我的公司广告政策不允许模拟。

这里是我使用的类。此外,您还需要检查并查看AppPool运行的进程是否有足够的权限进行模拟,因为它是一个特权活动。我会给应用程序池在临时管理员权限下运行的用户帐户(当然只有dev-box)看看它是否工作,这样你就知道这是否是权限问题

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
    }

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

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

从我在你的问题中看到的情况来看,你通过WindowsIdentity使用S4USelf获得了用户的令牌。然后,使用S4UProxy将模拟令牌传递给SQL server。既然你说你只得到了
ImpersonationLevel.Identification
,那就意味着你没有完成协议转换

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

有几件事需要检查

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

其次,您需要确保SPN设置正确。我知道你发布的链接只提到了你的ASP.NET服务帐户的SPN。实际上,您还需要确保SQL server上的服务帐户设置正确。另外,Windows根本不使用Kerberos身份验证。它将退回到使用NTLM。要在SQL server上正确设置SPN,有很多详细信息。你可以先查一查,看看运气如何。根据我的经验,大多数DBA不知道如何正确设置它们。他们甚至没有意识到这一点,因为大多数应用程序都可以很好地使用NTLM。您需要注意SQL server服务帐户及其使用的端口号

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

更新


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

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

当您向IIS进行身份验证时 使用集成服务器的服务器 身份验证,这会耗尽您的 第一跳。当IIS试图访问 一个网络设备,那将是 双跳或第二跳,但不是 允许。IIS无法依次传递 这些凭据将连接到下一个网络 设备,否则由开发人员或 管理员可能会滥用您的权限 凭据,并以以下方式使用它们: 网站访问者没有预料到

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