NegotiateStream 无法通过 SASL (POP3/IMAP/SMTP) 与 Kerberos/NTLM/GSSAPI 配合使用?

发布于 2024-09-10 20:24:05 字数 1727 浏览 9 评论 0原文

我正在尝试获取集成 Windows 身份验证(使用当前登录的 Windows 用户的默认凭据)来登录 Exchange 2007 帐户 (SMTP/POP3/IMAP)。

我已经为此实现了工作,但它使用 SSPI 函数,因此需要非托管代码权限(不好)。我尝试为此使用 NegotiateStream 类,但它不起作用。

您不能直接将 NegotiateStream 与 POP3/IMAP/SMTP 一起使用,因为整个对话中的每个请求和响应都需要包装在 base64 中并包含邮件协议后缀等。因此,我实现了自己的流类来执行此操作,并将其注入到 NetworkStream 和 NegotiateStream 之间。但是,我注意到 NegotiateStream 创建的请求及其期望的响应与我已成功使用的请求(以及由能够进行 NTLM/GSSAPI 类型身份验证的其他邮件客户端创建的请求)不同。

特别是,NegotiateStream 首先发送一个 5 字节长度的请求,其他实现不会发送该请求。此数据包被 Exchange 拒绝,并显示“协议错误”消息。

NegotiateStream 创建的第二个请求是正确的(以 NTLMSSP 开头)。因此,我决定忽略 Base64 编码中间流中的第一个数据包而不发送它。当 Exchange 收到第二个数据包时,它会成功处理该数据包并返回正确的连续响应。然而,这次 NegotiateStream 现在想要接收 5 字节的响应,而服务器返回的响应要大得多。简而言之,NegotiateStream 发送 +1 请求并期望 +1 响应。

我可以避免发送第一个“冗余”5 字节数据包,但我无法发明 NegotiateStream 期望的第一个 5 字节响应数据包。我尝试提供 NegotiateStream 之前尝试发送的相同数据包,但这当然不起作用。

我想了解发生了什么事以及如何解决这个问题。同样的行为也发生在 Windows XP SP3 和 Windows Server 2008 上。

我不是 Kerberos/GSSAPI 专家,但从我在文档中发现的内容来看,Kerberos 对话确实应该以 5 字节数据包开始。但是,我在使用其他工作工具时从未见过它,并且 Exchange 也拒绝它。也许,当 GSSAPI 在 SASL 协议上使用时(在 POP3/IMAP/SMTP 中用于身份验证),第一个数据包应该被省略?但是我如何告诉 NegotiateStream 此事,或者至少当它期望来自服务器的 5 字节响应时我应该向它发送什么?

我尝试了不同模式的 NegotiateStream,我还向 Exchange 发出了 AUTH NTLM 和 AUTH GSSAPI,但这一切都没有区别。其他工作实现(同时支持 GSSAPI 和 NTLM)都以相同的方式工作(GSSAPI 和 NTLM 数据包之间没有太大区别)。所有传入和传出的数据包都远大于 5 个字节。

我还在 Windows XP 上尝试使用 IIS SMTP 服务,结果相同。基于 SSPI 的非 NegotiateStream 实现可以工作,而 NegotiateStream 由于第一个数据包而不能工作。如果我不发送它,我不知道 NegotiateStream 期望什么作为第一个响应。

我曾经认为应该可以使其工作,因为 SmtpClient 类可以以某种方式管理它并使用默认凭据和 NTLM 进行身份验证。但我发现 SmtpClient 内部并不使用 NegotiateStream,它只是进行非托管 SSPI 调用,就像我在旧版本的软件中所做的那样。

也尝试过 Visual Studio 2010 / .NET 4.0。运气不好(并且没有新的方法/属性来微调 NegotiateStream 中的内容)。

我完全迷失了:-(

I'm trying to get Integrated Windows Authentication (using default credentials of the currently logged Windows user) to log in Exchange 2007 account (SMTP/POP3/IMAP).

I already have working implementation for this but it uses SSPI functions and thus needs unmanagedcode permissions (no good). I tried to make use of NegotiateStream class for this but it does not work.

You can't directly use NegotiateStream with POP3/IMAP/SMTP as every request and response in the entire conversation needs to be wrapped in base64 and embraced with the mail protocol suffixes, etc. So, I implemented my own stream classes which does this, and injected it between NetworkStream and NegotiateStream. However, I noticed that the requests created by NegotiateStream and responses which it expects are different from those ones I have been successfully using (and those created by other mail clients which are capable of NTLM/GSSAPI sort of authentication).

In particular, NegotiateStream first sends a 5-byte length request which is not sent by other implementations. This packet is rejected by Exchange with "protocol error" message.

The second request created by NegotiateStream is the correct one (starts with NTLMSSP). So, I decided to ignore the first packet in my base64-encoding intermediate stream and not send it. When Exchange gets the second packet, it eats this packet successfully and returns the proper continuation response. However, this time NegotiateStream now wants to receive 5-bytes response while the server returned much larger response. Shortly speaking, NegotiateStream sends +1 request and expects +1 response than it should.

I can avoid sending the first "redundant" 5-bytes packet but I cannot invent the first 5-bytes response packet expected by NegotiateStream. I tried to feed the same packet NegotiateStream attempted to send before but this of course didn't work.

I want to find out what's going on and how to fix this. The same behavior occurs on Windows XP SP3 and Windows Server 2008.

I'm not Kerberos/GSSAPI expert but from what I found in the docs it seems Kerberos conversation should indeed start with a 5-bytes packet. However, I never saw it when using other working tools and Exchange rejects it too. Maybe, when GSSAPI is being used over SASL protocol (used in POP3/IMAP/SMTP for authentication), the first packet should be omitted? But how can I tell NegotiateStream about this or at least what should I send to it when it expects that 5-bytes response from the server?

I tried different modes of NegotiateStream, I also issued both AUTH NTLM and AUTH GSSAPI to Exchange but this all makes no difference. And other working implementations (which support both GSSAPI and NTLM) all work the same way (there is no big difference between GSSAPI and NTLM packets). All incoming and outgoing packets there are much larger than 5 bytes.

I also tried with IIS SMTP service on Windows XP with the same result. SSPI-based non-NegotiateStream implementations work while NegotiateStream doesn't due to the first packet. If I do not send it, I have no idea what NegotiateStream expects as the first response.

I once thought it should be possible to make it work as SmtpClient class can manage this somehow and authenticate with the default credentials and NTLM. But I found that SmtpClient does not internally use NegotiateStream, it just makes unmanaged SSPI calls, just like I do in the old version of my software.

Tried with Visual Studio 2010 / .NET 4.0 as well. No luck (and no new methods/properties to fine-tune things in NegotiateStream).

I'm completely lost :-(

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

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

发布评论

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

评论(1

强者自强 2024-09-17 20:24:05

我不确定问题到底是什么。您想要/必须使用 NegotiateStream 编写自己的实现吗?或者您只需要使用带有 SMTP/IMAP/POP3 的 GSSAPI/Kerberos 身份验证?在这种情况下,支持 GSSAPI 并使用 Exchange 服务器进行测试的邮件组件(例如我们的 Rebex Secure Mail)可能是一个不错的选择并且可以节省时间。

以下代码将使用 GSSAPI 连接并登录到 Exchange 服务器 SMTP:

Smtp smtp = new Smtp();
smtp.Connect("yourserver");
smtp.Login("username","password", SmtpAuthentication.GssApi);

...
smtp.Disconnect();

I'm not sure what exactly is the question. Do you want/have to write your own implementation using NegotiateStream? Or do you only need to use the GSSAPI/Kerberos authentication with SMTP/IMAP/POP3? In such case a mail component which supports GSSAPI and which is tested with Exchange server (such as our Rebex Secure Mail) might be a good choice and a time-saver.

Following code will connect and login to Exchange server SMTP using GSSAPI:

Smtp smtp = new Smtp();
smtp.Connect("yourserver");
smtp.Login("username","password", SmtpAuthentication.GssApi);

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