Jon Skeet said:
But we know the OP is in the first category, don't we?
Yes I do, and I dis answer his question ,didn't I? But this is a different (albeit related)
issue.
First my excuses for the long post's and the long thread, but I think it's important enough
to be somewhat explicit.
My point is about the common sense of using LDAP for authentication, more specifically using
LDAP 'bind' to authenticate which, even if "it works", is not the most appropriate way to
authenticate, even not on NON Windows systems.
Unfortunately, even on MSDN (see patterns & Practices at
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT02.asp )
you'll find samples of asp.net using AD authentication which goes like this:
<snip
string domainAndUsername = domain + @"\" + username;
DirectoryEntry entry = new DirectoryEntry( _path,
domainAndUsername,
pwd);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
</snip
Above code uses LDAP "bind" to authenticate the "domainAndUsername" but the code is
flawned, why?
1) It's not pure authentication request, it's an *authorization* request (authenticate +
access check), if the the _path is protected by an ACL which does not grant access for
domainAndUsername, the "authentication will fail albeit the user credentials are perfectly
legitime, bummer!
2) DirectoryEntry sit's in top of the ADSI COM client stuff (activeds.dll), part of a
successful bind is the transfer of the AD metadata (the directory schema) to be cached at
the client (per process/ApplicationDomain), this is done to speed-up consecutive requests
against the Directory. The schema is a something like ~100Kb of data, quite a bit of data
just to authenticate a client, right? Result, a scalability issue.
3) But there is more, if the bind fails for one or another reason, the client (ADSI in this
case) produces a "default" minimal schema and stores it in the cache (again per
process/ApplicationDomain), however this schema doesn't reflect the real AD schema. The
result is that successful binds following the unsuccesful bind (this is an asp.net
application right), will use the "default schema" instead of the real AD schema and will get
some weird errors (NO_SUCH_PROPERTY or NO_SUCH_OBJECT ) when trying to query the directory.
Many have been bitten by this, especially those using ADSI (and System.DirectoryServices) to
bind and query non AD servers.
The sample above continuous like :
....
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if(null == result)
....
Great, the user whas correctly authenticated, and now we are going to perform a look up for
the same user, the authentication above was done against the LSA (the security provider on
Windows) and apparantly the author thinks it necessary to check whether the user is also
stored in this Directory. The chapter in this document is called - To develop LDAP
authentication code to look up the user in Active Directory -. English is not my first
language, but as far as I see it, this implies two different tasks "authentication" and
"Lookup". The lookup is not needed if you only want to authenticate, right?.
Now, the above code was written for V1.1 of the framework, V2 was added the LDAP low level
stuff through the System.DirectoryServices.Protocols, unfortunately above is used frequently
to authenticate from asp or asp.net, but in V2 we can solve issues 2 and 3 above, by coding
something like:
...
// Bind to an LDAP server
using (LdapConnection ldap = new LdapConnection("LdapServerName"))
{
LdapSessionOptions so = ldap.SessionOptions;
ldap.AuthType = AuthType.Basic; // or Ntlm, Kerberos etc... depending on the SSP
ldap.Bind(new NetworkCredential("userName", "UserPAwd"));
}
Look, no ADSI stuff under the cover, though this code is much closer to what we are trying
to achieve, that is *authenticating*, we still we may face issue 1, the authentication is
done against a Security Provider (using the SSPI on Windows), but the bind is done to the
root of the directory (AD or None-AD) and if this one is protected by ACL's, the Bind may
fail resulting in a false negative.
The only way to solve this is by authenticating using the SSPI and selecting Kerberos ,
Secure Channle (SSL) or a custom provider interface to authenticate against Windows or
Non-Windows Security Providers.
Willy.