I have been occasionally thinking about LDAP recently; in particular the interdependency of LDAP and SQL. (and the cftransaction issues)
As I already noted there is a fundamental problem with using transactions with out of step error conditions.
I have noticed some bizarre and inconsistent behaviour.
1) If you put in a badly formatted filter Coldfusion returns “Connection to ldap server failed.” 84596
The ldap server is returning: searchResDone(2) protocolError (Bad search filter) [0 results]
The Coldfusion returns an Application Error: “Connection to ldap server failed.” It is throwing a coldfusion.tagext.net.LdapTag UnknownHostException.
This is precisely the same error if you put a nonexistant (invalid) server in. Also the same error if you put a dodgy port number. In fact for all ldap errors the only catches that will catch this are “Application” or “Any”.
2) LDAP Timeout 84595
The ldap timeout seems to me like a whole pile of steaming defication.
One might assume, that the timeout would throw an error, it doesn’t. One might assume that if the timeout expired no results would be found, wrong again.
Like a database in firehose mode data will spew back until the timeout expires. Unlike the database example the CFLDAP tag with a timeout is a dribbly firehose mode; data continues to spew back for a little while; usually about a second. So setting a timeout of 1 microsecond (1/1000 of a second) I would expect to recieve no results (and a timeout). What I get is about 8-20 results – it depends – and obviously no timeout.
If you thought we were doing this before. We weren’t; we were just collecting the requesttimeout; after the ldap request had completed. Long after the page had timed out.
Example Code
If you would like to test this for yourself I enclose the following:
<cfparam name="variables.ServerName" default="<server>">
<cfparam name="variables.BindUserName" default="cn=Directory Manager">
<cfparam name="variables.BindPassword" default="<bind password>">
<cfsetting enablecfoutputonly="yes">
<cftry>
<cfset variables.filter = "(uid=*****)">
<cfset variables.LDAPDNSuffix = "ou=<COMPANY>, o=<object>">
<cfset start = gettickcount()>
<!--- Check LDAP --->
<cfldap
server="FAILFAILFAIL#Trim(variables.ServerName)#"
username="#Trim(variables.BindUserName)#"
password="#variables.BindPassword#"
start="#variables.LDAPDNSuffix#"
filter="#variables.filter#"
scope="subtree"
action="query"
name="qPing"
attributes="dn,sn,lc"
timeout="1">
<cfset end = gettickcount()>
<!--- Success --->
<cfdump var="LDAP processing time #start - end#">
<cfdump var="#qPing#" top="4">
<!--- Catch --->
<cfcatch type="any">
<cfdump var="#cfcatch.type#">
<cfdump var="#cfcatch#">
<cfabort>
</cfcatch>
</cftry>
How to catch an error
If you want to catch an ldap error:
To catch bad filter strings, invalid hosts, odd ports, invalid usernames or passwords. (usernames and passwords message is different – Authentication failed:[LDAP: error code 49 - Invalid Credentials]. Also the underlying (java) error type is InvalidCredentialsException, although this is not readily available.
you must catch “Application” or “Any”. There is no easy way to seperate the errors. You could parse the messages for authentication problems. But for all the others. You’re basically rudderless.
How to catch a timeout
You can’t really use the timeout. What’s the point in getting the top 8-20,20-100,100-1000 results via the timeout? There is a maxrows attribute. My main concern is that; without an order there is no expectation of consistency. Unless you have a very very good reason – it’s best to stay well clear.
Is there a solution?
Well I have a proposal; it’s a little convoluted. What I suggest is that we build a ldap.cfm in the CustomTags directory.
This does a CFThread – running the ldap request in a new tag. Killing it from the master, after a sleep, if it doesn’t finish in the specified time.
The final part of my solution is that I have submitted these bugs to Adobe. Votes on:
http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=84595
http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=84596
would be much appreciated.