Mixed Metaphors
What’s the difference between the following strings:
- ldap://myserver.mycompany.com/
- ldap://myserver.mycompany.com
- LDAP://myserver.mycompany.com/
- LDAP://myserver.mycompany.com
Give up? Several hours of debugging, that’s what. In the .NET world, the System.DirectoryServices namespace contains classes named DirectoryEntry and DirectorySearcher. To search an LDAP directory, you created a DirectoryEntry based on the server address and DN to specify the root of your search, and then create a DirectorySearcher, passing in the DirectoryEntry to the constructor. This can be used to search any ldap directory. So, you would think that you could pass in any valid LDAP URL into the DirectoryEntry class, right? Wrong. Microsoft’s implementation of the DirectoryServices namespace is build upon ADSI. So, the URL you’re passing in isn’t a typical URL at all. It’s based on the ADSI connection string, which, if you want to search LDAP, must be use the prefix LDAP:// in all upper case. Additionally, unless you are specifying a base DN to search, you can NOT have the trailing / on the end of the URL. If you do either of these things wrong, your code will raise a not-too-informative exception. So, only the last element on the above list will work.
Your concerns will generally end there if you are querying an LDAP directory that isn’t an Active Directory. Because System.DirectoryServices is based off of ADSI, the underlying code tries to do a lot of annoying things, even if you explicitly tell it not to. One thing it loves to do is try to authenticate you using Kerberos, even if you specify to the bind operation that you want to use the Anonymous or None types from the AuthenticationTypes enumeration. This doesn’t affect desktop applications much, but can be really annoying for web apps, which run under the IUSR or ASPNET account (not sure which it uses for ADSI). I managed to get my application to work around this restriction, but I really don’t remember off the top of my head how. If you really are curious, drop me an e-mail and I’ll look it up.
Another problem with the DirectoryServices namespace that I’ve run across is that specifying a base DN in the connection string has some restriction on it that I haven’t figured out that will cause a very informative exception (Error Code 0×80005000, which apparently means “Table Not Found”, or something to that effect). I’ve had situations where:
- LDAP://myserver/dc=dir,dc=company,dc=com
works - LDAP://myserver/cn=me,ou=people,o=org,dc=dir,dc=company,dc=com
works
- LDAP://myserver/o=org,dc=dir,dc=company,dc=com
gives a connection error
I assume it has something to do with the objectclass of the node I’m trying to bind to, but I’m not sure what.
It would be nice if the System.DirectoryServices implementation treated LDAP like LDAP instead of assuming that you really want strong authentication and only want to bind to certain types of objects to perform a search. Or, at least, it would be nice if there was a way to explicitly specify in the code that you want to treat an AD server like a general LDAP server.