views:

143

answers:

1

Hi everyone!

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 :-(

A: 

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();
Martin Vobr
I need to authenticate with the default credentials of the currently logged Windows user, not using any unmanaged calls. It's not a problem to write the managed version if you have the password. If you don't have that password, you have to either use unmanaged calls or find a way to employ .NET functions do this for you. I'm looking for the second way (as I already have a managed code implementation which is working fine with explicitly specified login and password).
Alex Orlov
Looks like your component is capable of authenticating with the default credentials but I'm not sure if it simply works via SSPI (and thus nearly useless with nowadays habits of disallowing unmanaged calls for .NET applications due to security reasons)? The key question is whether your implementation is managed or not? I already mentioned in my original post that I'm not interested in an unmanaged implementation as I already have the working one (but the fact it makes unmanaged calls makes the whole idea useless).
Alex Orlov
Kerberos/NTLM/GSSAPI in Rebex Secure Mail works via unmanaged SSPI calls. We don't have a managed implementation, unfortunately. Actually, we first tried the same approach you are now trying to get working (using special stream classes to get individual packets from .NET's NegotiateStream) and spent few days on this, but couldn't get it to work with POP3/IMAP/SMTP and Exchange either. So we implemented it via SSPI instead. Sadly, this means that Rebex Secure Mail isn't a solution to your problem.
Lukas Pokorny
Thanks for the reply. It was still helpful anyway. At least I now know that it wasn't my fault of not understanding NegotiateStream class). It turns out that it indeed cannot be used for this as I now know that other smart guys (you) weren't able to succeed in this too.
Alex Orlov
BTW, when I looked at your components, I was impressed with the online documentation. How did you manage to get things like working links to the standard classes like "string" (which points exactly to http://msdn2.microsoft.com/en-us/library/s1wwdcbf, quite unobvious path to construct)? I tried nDoc tool but it generates links which can only work if you have .NET 1.1 documentation installed locally.
Alex Orlov
ndoc used to be fine but AFAIK is no longer developed. Try using directly sandcastle (it's not as easy to get working as ndoc but it has nice tooling ecosystem around it). Sandcastle Help File Builder is worth checking - http://shfb.codeplex.com/ - we are using it too. It will help you generating links to MSDN.
Martin Vobr
Thanks, will take a look! BTW, I've been able to make NegotiateStream work with Exchange's NTLM via SASL and default credentials (but not with Exchange's Kerberos which is my real desire as it's the only supported auth method in Exchange 2010).
Alex Orlov
Phew, lucky day though. Got Kerberos working too. I've been struggling and giving up, then getting back to it for two weeks. And it's working now. Managed implementation of NTLM and GSSAPI/Kerberos is possible :)
Alex Orlov
Congratulation, Alex!
Martin Vobr