Migrating to Negotiate from NTLM is quite simple in most cases. It breaks down into these four simple steps:
First, build an SPN for your Service
When I talk to people about using Negotiate, there’s often this moment of terror when they realize they’re going to have to build an SPN. I’ve got my theories about why that might be, but suffice it to say you can hold back the terrors. It’s not difficult, and it corresponds to about 90% of the work here.
The first thing you have to do is pick an SPN prefix. This should be something unique to your application protocol. For example, if I have an application called “Flying Authentication Thing”, then FlyingAuthenticationThing would be a useful (if not particularly short) SPN prefix.
The prefix is half the work of building an SPN. The other half is literally putting that prefix in front of your server’s hostname (DNS preferred, netbios if necessary).
would denote the FlyingAuthenticationThing service on my current development machine. You can do this with the explicitly-blessed DsMakeSpn (see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ad/ad/dsmakespn.asp), or a simple sprintf.
Second, have your Service register the SPN
The SPN needs to be associated with the account your server is running as. If this is NetworkService or LocalSystem, that would be the host computer’s account (usually netbios computername$) in the Directory.
Register your SPN when the service gets installed. You only have to do it once.
You can use DsWriteAccountSpn (see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ad/ad/dswriteaccountspn.asp?frame=true) to register that SPN. There should already be SPNs on the machine account already. Don’t disturb them… just add yours to the mix.
The cool thing about registering your SPN is that it’s generally fire-and-forget. If your computer changes names for some reason, most of the SPNs will automatically change with it.
Alternatively, you can use setspn (a reskit tool, see http://www.microsoft.com/windows2000/techinfo/reskit/tools/existing/setspn-o.asp) to write the SPN manually, since you only have to do it at installation time.
Third, have your client use the Service’s SPN.
This may seem obvious, but to get Mutual Auth, you have to actually provide the server name to the client authentication mechanism. It can’t just guess J
So, when you’re going to connect to a server (netbios name or dns name), build an SPN out of it the same way your server did above. That is, slap your SPN prefix onto the front of it with a slash in the middle.
Pass the newly-built SPN to your authentication function. In SSPI terms, this would be InitializeSecurityContext’s pszTargetName parameter. Wrappers around SSPI have their own parameters—consult your API documentation.
Fourth, have your Client and Server call Negotiate instead of NTLM
Whatever your client or server calls with NTLM, have it call it with Negotiate instead.
In SSPI terms, this means changing the call to AcquireCredentialsHandle to have “Negotiate” instead of “NTLM”. For RPC, DCOM, or other callers, it will be different, but usually just as simple – swapping, say, RPC_C_AUTHN_WINNT with RPC_C_AUTHN_GSS_SPNEGO.
Consult your API documentation for more on this if you don’t use SSPI directly, since there are lots of functions that wrap SSPI in some way.
…and that’s it! You’re done!
One of the cool things about Negotiate is that it tends to know when it’s necessary (and safe) to downgrade to NTLM. One of those cases is when no SPN is registered on a server’s account. In those cases, the server is obviously downlevel (that is, it hasn’t registered an SPN yet), so NTLM will be used. So uplevel clients can talk to downlevel servers.
Also, because Negotiate is smart enough to accept raw (non-gss-framed) NTLM, the reverse is also true: a downlevel client can talk to an uplevel server. This makes migration far less painful than one might expect from changing authentication protocols.