Monday, August 07, 2006

Authentication Mechanisms in SDS

In ADSI and System.DirectoryServicess (SDS), we are really only given two choices for how authentication will be performed when we do a bind operation.  We can specify the "Secure" flag (AuthenticationTypes.Secure), and ADSI will attempt to the bind to the remote directory using Windows SSPI authentication with the Negotiate protocol.  As you may know, the Negotiate protocol is the primary authentication protocol in Windows since Windows 2000 and selects between using Kerberos (always preferred) and NTLM (there for backwards compatibility).  For the really nerdy of you out there, the Negotiate protocol is implemented by Microsoft's LDAP API using the GSS-SPNEGO SASL mechanism.

The other option in SDS is to NOT specify AuthenticationTypes.Secure and it will attempt to use an LDAP simple bind instead*.  The only authentication mechanism defined by LDAP specification is the simple bind, so every directory implements it.  As such, it ends up being the cross-platform lowest common denominator approach.  The problem with the simple bind is that it is totally insecure by itself.  Simple bind passes the user's plaintext credentials on the network, so unless some sort of channel encryption is provided (like SSL, the defacto cross-platform standard here as well), anyone who can sniff the wire traffic can recover the user's password.  This sort of thing is generally frowned on my security enthusiasts.  :(

Digest Authentication in LDAP API/SDS.P

There is, however, a richer set of authentication mechanisms supported by Microsoft's LDAP API than what ADSI/SDS get to use, and these are available to System.DirectoryServices.Protocols (SDS.P).  One of the most interesting of these is the Digest authentication protocol.  Digest is a standard, secure authentication protocol that does not involve the exchange of plaintext credentials and is implemented by AD and ADAM, as well as some other LDAP directories.  In SDS.P, we can use it very easily.  Here is a short sample illustrating this (and no, there is no ADAM instance at adam.joekaplan.net; dream on...):

public static bool DoDigestAuth(NetworkCredential cred)
{
    const int LDAP_INVALID_CREDENTIALS = 49;
    LdapConnection conn =
        new LdapConnection("adam.joekaplan.net:389");
    conn.AuthType = AuthType.Digest;
    conn.Credential = cred;

    try
    {
        conn.Bind();
        return true;
    }
    catch (LdapException ex)
    {
        if (ex.ErrorCode == LDAP_INVALID_CREDENTIALS)
        {
            return false;
        }
        else
        {
            throw;
        }
    }
}

Here, we have a trivial little sample that shows how this might be done.  Note that we probably wouldn't create a new LdapConnection object each time this is called and we'd also try to find a way to clean that up with a proper Dispose, but the point here is to illustrate that all we really have to do is set the AuthType property to AuthType.Digest and it works.  The credentials are specified with a standard NetworkCredential object.  For Digest, just specify the username and password, not the domain parameter.

Why is This Important?

Digest authentication is really interesting particularly for ADAM, as it is supported by ADAM principals.  Before ADAM supported Digest auth (as of SP1), the only way to authenticate an ADAM principal was with a simple bind.  That wasn't secure (see above), so SSL was required to make it secure.  However, SSL certs are not always easy to procure and take extra effort to install, so many people were missing this and were insecure.  :(

The other cool thing with Digest is that since it is implemented through Microsoft's SSPI model, it can also be used as a mechanism for getting channel encryption and signing, just like negotiate auth supports today**.  This means that not only can you get secure binding for free, but all of your network traffic after the bind can be encrypted and signed for free (no SSL required).  This is done through setting the Signing and Sealing properties to true on the LdapSessionOptions class.  This, in turn, allows a way to do LDAP password operations on ADAM principals without using SSL and without having to change the setting in ADAM to turn off the requirement for a secure channel on password ops (another big security frown sandwich there...). 

One great scenario for this feature would be to use it with ADFS for their ADAM Account Store support.  This would allow secure authentication without requiring SSL out of the box and would also provide free channel encryption.  Product team please take note!

* There is a feature in Windows Server 2003 SP1 ADSI will try Digest auth when the Secure flag is specified and ADSI detects that the server supports Digest but not negotiate auth.  However, this doesn't help us for AD or ADAM, since they both support negotiate auth.  The problem with negotiate auth for ADAM is that it is only used for authenticating Windows users, not ADAM principals.

** There appears to be a bug in the implementation in ADAM SP1 where the channel encryption feature only works if the network traffic is NOT on the loopback (localhost) port.  This is different from the way negotiate channel encryption works.  This appears to be an oversight in the implementation and not an underlying issue in the design, so presumably this will get fixed someday.

Monday, August 07, 2006 2:31:20 PM (Central Daylight Time, UTC-05:00)  #    Comments [0]  |  Tracked by:
http://9uags-le-informazioni.info/58397612/index.html [Pingback]

Theme design by Jelle Druyts