Authentication Using SSPI

When authenticating against Active Directory, we can use a couple of techniques in order to validate a user's credentials using native Windows protocols rather than LDAP. One valid technique is to use the LogonUser API. This technique is fairly well understood, and resources like www.pinvoke.net have ready-made code snippets that demonstrate how to use the API successfully. We won't cover this technique, other than to say that for Windows 2000, this technique has some fairly significant limitations. This topic and more are covered in detail in The .NET Developer's Guide to Windows Security. While these limitations have been removed with subsequent Windows releases, we feel that an easier technique is available that addresses all NT-based versions of Windows.

SSPI authentication has become much easier with .NET 2.0, and it is a handy way to sidestep any security issues that crop up with LogonUser. While this technique really is not LDAP or ADSI related in any sense, it is certainly useful enough to merit coverage. Essentially, we will use the new NegotiateStream class in .NET 2.0 to harness the Negotiate protocol directly. The trick here is to execute a trusted handshake, acting as both the client and the server. Listing 12.6 shows a sample of how this might work.

Listing 12.6. Windows Authentication Using SSPI

using System; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Principal; using System.Threading; class NTAuth { TcpListener listener; int port; public NTAuth(int port) { this.port = port; this.listener = new TcpListener( IPAddress.Loopback, this.port); this.listener.Start(); } private void CreateServer(object state) { try { NegotiateStream nsServer = new NegotiateStream( this.listener.AcceptTcpClient().GetStream() ); nsServer.AuthenticateAsServer( CredentialCache.DefaultNetworkCredentials, ProtectionLevel.None, TokenImpersonationLevel.Impersonation ); } catch (AuthenticationException) {} } public bool Authenticate(NetworkCredential creds) { TcpClient client = new TcpClient( "localhost", this.port ); ThreadPool.QueueUserWorkItem( new WaitCallback(CreateServer) ); NegotiateStream nsClient = new NegotiateStream( client.GetStream(), true ); using (nsClient) { try { nsClient.AuthenticateAsClient( creds, creds.Domain + @"" + creds.UserName, ProtectionLevel.None, TokenImpersonationLevel.Impersonation ); return nsClient.IsAuthenticated; } catch (AuthenticationException) { return false; } } } }

The SSPI authentication technique will not work with ADAM security principals. As such, this technique applies only to Active Directory installations.

Категории