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.
Part I: Fundamentals
Introduction to LDAP and Active Directory
Introduction to .NET Directory Services Programming
Binding and CRUD Operations with DirectoryEntry
Searching with the DirectorySearcher
Advanced LDAP Searches
Reading and Writing LDAP Attributes
Active Directory and ADAM Schema
Security in Directory Services Programming
Introduction to the ActiveDirectory Namespace
Part II: Practical Applications
User Management
Group Management
Authentication
Part III: Appendixes
Appendix A. Three Approaches to COM Interop with ADSI
Appendix B. LDAP Tools for Programmers
Appendix C. Troubleshooting and Help
Index