我可以模拟通过表单身份验证进行身份验证的客户端并建立与 SQL Server 的可信连接吗?

发布于 2024-10-16 08:50:31 字数 1516 浏览 4 评论 0原文

这是我一直在尝试做的事情

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

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

在生产设置中部署到 Windows 2008 (IIS7) 之前,我正在我的开发计算机(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 服务器上存在设置问题。内部异常是不允许请求的注册表访问

如果我设置断点并在 Impersonate() 调用后检查 WindowsIdentity,我会看到 ImpersonationLevel 设置为 Identification.这似乎表明它设置不正确。有人能证实吗?

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

Here is what I've been trying to do

Build an ASP.NET MVC 3 application with forms authentication and active directory membership. The web server and database are different physical servers hence a double hop.

I thought the answer was this older article on constrained delegation and protocol transition? So far, I have not been able to get the technique to work.

I'm testing this from my DEV machine (Windows 7, IIS7) for the web server before deploying to windows 2008 (IIS7) in the production setup. Would windows 2008 make a difference?

What works and what fails

I'm able to login with forms auth and the AD membership. This seem to be working fine. When I try to make a database call using this code:

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();
                }
            }
        }
    }

It fails with an exception leading me to believe I have setup issues on my local DEV server. The inner exception is Requested registry access is not allowed.

If I set a breakpoint and inspect the WindowsIdentity after the Impersonate() call I see that the ImpersonationLevel is set to Identification. This seems like a clue that it is not setup correctly. Can anyone confirm?

Am I on the right track and is this even possible to setup? Any pointers would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一指流沙 2024-10-23 08:50:31

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

我假设您正确配置了 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 权限,以确保它可以创建 Impersonation 类型的 WindowsIdentity。你可以尝试一下。

I think you are on the right track. You just need more troubleshooting work on your protocol transition setup.

I assume you configured your Active Directory membership provider correctly so that you can successfully logon your web page using the active directory user name and password. If that's not the case, please ignore the rest of my answer :)

From what I saw in your question, you got your user's token using S4USelf by WindowsIdentity. Then, you are using S4UProxy to pass the impersonated token to SQL server. Since you said you got ImpersonationLevel.Identification only, it means you failed to do protocol transition.

You need to understand that allowing one machine to do protocol transition in a domain is very high privilege. Granting a server to do protocol transition almost means that you trust that server to be almost like a domain controller. You need to consciously make this decision in AD to turn a server to have this ability and you have to be a domian administrator to make this change. If you haven't done this, you probably didn't setup your thing properly.

There are couple things to check.

First, make sure you selected "Trust this computer for delegation to specified services only" and then you picked "select Use any authentication protocol" on your service account. You may like to create a domain account. Here is a link on how to create a service account for ASP.NET. Remember, you need a domain account. After you created a domain service account, make sure you go to the delegation tab on that account and selected the correct options.

Second, you need to make sure SPNs are set properly. I realize that the link that you posted only mention the SPN of your ASP.NET service account. Actually, you also need to make sure the service account on your SQL server also set properly. Otheriwse, Windows won't use Kerberos authentication at all. It will fall back to use NTLM. There are a lot of details to setup a SPN correctly on SQL server. You can check here first and see if you have any luck. From my experience, most of the DBA don't know how to set them up properly. They don't even aware of it because most applications work fine with NTLM. You need to pay attention to the SQL server service account and the port number that it's using.

Third, you need to make sure there is nothing disabling your Kerberos delegation. Some sensitive AD accounts are by default not allowed to be delegated. For example, the built-in administrator account. So, you better use some other normal user accounts for testing purpose.

UPDATE

I just found another article teaching you how to setup the protocol transition for ASP.NET. It mentioned that you need to grant TCB right to the IIS service account in order to make sure it can create a Impersonation type WindowsIdentity. You can give it a shot.

吲‖鸣 2024-10-23 08:50:31

这是我使用的类。此外,您还需要检查运行 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
    }

Here the class I use. Also, you'll want to check and see if the process that the AppPool is running under has enough permission to do the impersonation since it is such a privileged activity. I would give the user account that the app pool is running under temporary admin privileges (dev box only of course) and see if it works so you'll know if it is a permissions issue.

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
    }
浅笑轻吟梦一曲 2024-10-23 08:50:31

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

Have you enabled Impersonation on the Windows 7 or Windows 2008 machine? This article covers how to set it up. http://technet.microsoft.com/en-us/library/cc730708(WS.10).aspx. Also, are you running 32-bit or 64-bit?

玩心态 2024-10-23 08:50:31

您还应该咨询您的 AD 管理部门,看看是否允许模拟。我公司的 AD 政策不允许冒充。

You should also check with your AD administration to see if Impersonation is allowed. My companies AD policies won't allow impersonation.

梦回梦里 2024-10-23 08:50:31

我认为你已经发现了这个问题,但没有人提到它。 “双跳”问题不允许您这样做。这是不可能的。有很多人写过关于它的文章,例如 斯科特·福赛思

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

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

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

I think you have identified the problem but no one has mentioned it. The "double hop" issue is not going to allow you to do this. It's not possible. There are lots of people who have written about it such as Scott Forsyth.

When you authenticate to the IIS
server using Integrated
Authentication, that uses up your
first 'hop'. When IIS tries to access
a network device, that would be the
double or second hop which is not
allowed. IIS cannot in turn pass on
those credentials to the next network
device, otherwise the developer or
administrator could abuse your
credentials and use them in ways that
the site visitor didn't anticipate.

This doesn't occur with anonymous
access or with impersonation off
because in that case IIS takes care of
authenticating you and then it uses a
different user for local or network
access. This means that the app pool
identity or anonymous user can make a
network call as the first hop.

I think it's pretty clear that you cannot pass your credentials any further than the first connection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文