LDAP

A form can retrieve data from LDAP server(s) to display or to save them. Configuration options for LDAP will be specified in the parameter field of the Form and/or the FormElement. Definitions of the FormElement will overwrite definitions of the Form. One LDAP Server can be configured per FormElement. Multiple FormElements might use individual LDAP Server configurations.

To decide which Parameter should be placed on Form.parameter and which on FormElement.parameter: If LDAP access is …

  • only necessary in one FormElement, most useful setup is to specify all values in that specific FormElement,
  • needed on multiple FormElement*s (of the same *Form, e.g. one input with typeAhead, one note and one action), it’s more efficient to specify the base parameter ldapServer, ldapBaseDn in Form.parameter and the rest on the current FormElement.
Parameter Example Description Form FormElement Used for
ldapServer directory.example.com Hostname. For LDAPS: ldaps://directory.example.com:636 x x TA, FSL
ldapBaseDn ou=Addressbook,dc=example,dc=com Base DN to start the search x x TA, FSL
ldapAttributes cn, email List of attributes to save in STORE_LDAP x x FSL
ldapSearch (mail=john.doe@example.com) Regular LDAP search expression x x FSL
ldapTimeLimit 3 (default) Maximum time to wait for an answer of the LDAP Server x x TA, FSL
ldapUseBindCredentials ldapUseBindCredentials=1 Use LDAP_1_* credentials from config.qfq.php for ldap_bind() x x TA, FSL
typeAheadLdap   Enable LDAP as ‘Typeahead’ data source   x TA
typeAheadLdapSearch (|(cn=*?*)(mail=*?*)) Regular LDAP search expression, returns upto typeAheadLimit x x TA
typeAheadLdapSearchPrefetch (mail=?) Regular LDAP search expression, typically return one record x x TA
typeAheadLdapSearchPerToken  
Split search value in token and OR-combine every search with
the individual tokens
x x TA
typeAheadLdapValuePrintf ‘%s / %s’, cn, mail Custom format to display attributes, as value x x TA
typeAheadLdapIdPrintf ‘%s’, mail Custom format to display attributes, as id x x TA
typeAheadLimit 20 (default) Result will be limited to this number of entries x x TA
typeAheadPedantic typeAheadPedantic=0 Turn off ‘pedantic’ mode - allow any values (see below) x x TA
typeAheadMinLength 2 (default) Minimum number of characters before starting the search x x TA
fillStoreLdap   Activate Fill STORE LDAP with the first retrieved record   x FSL
  • typeAheadLimit: there might be a hard limit on the server side (e.g. 100) - which can’t be extended.
  • ldapUseBindCredentials is only necessary if anonymous access is not possible. RDN and password has to be configured in config.qfq.php.

Typeahead (TA) - LDAP

See also Type Ahead

Typeahead offers continuous searching of a LDAP directoy by using a regular FormElement of type text. The FormElement.parameter*=*typeAheadLdap will trigger LDAP searches on every user keystroke (starting after typeAheadMinLength keystrokes) for the current FormElement - this is different from dynamicUpdate (triggered by leaving focus of an input element). Typeahead delivers a list of elements.

  • FormElement.parameter.typeAheadLdap - activate the mode Typeahead - no value is needed, the existence is sufficient.
  • Form.parameter or FormElement.parameter:
    • ldapServer = directory.example.com
    • ldapBaseDn = ou=Addressbook,dc=example,dc=com
    • typeAheadLdapSearch = (|(cn=*?*)(mail=*?*))
    • typeAheadLdapValuePrintf = ‘%s / %s’, cn, email
    • typeAheadLdapIdPrintf = ‘%s’, email
    • Optional: ldapUseBindCredentials = 1

All fetched LDAP values will be formatted with:

  • typeAheadLdapValuePrintf, shown to the user in a drop-down box and
  • typeAheadLdapIdPrintf, which represents the final data to save.

The id/value translation is compareable to a regular select drop-down box with id/value pairs. Only attributes, defined in typeAheadLdapValuePrintf / typeAheadLdapIdPrintf will be fetched from the LDAP directory. To examine all possible values of an LDAP server, use the commandline tool ldapsearch. E.g.:

ldapsearch -x -h directory.example.com -L -b ou=Addressbook,dc=example,dc=com "(mail=john.doe@example.com)"

All occurrences of a ‘?’ in ldapSearch will be replaced by the user data typed in via the text-FormElement. The typed data will be escaped to fulfill LDAP search limitations. Regular Form variables might be used on all parameter and will be evaluated during form load (!) - not at the time when the user types something.

Pedantic

The typeAheadPedantic mode ensures that the typed value (technically this is the value of the id, latest in the moment when loosing the focus) is valid (= exists on the LDAP server or is defined in typeAheadSql). If the user typed something and that is not a valid id, the client (=browser) will delete the input when losing the focus. To identify the exact id, an additional search filter is necessary: typeAheadLdapSearchPrefetch - see next topic.

typeAheadPedantic is active by default when typeAheadLdap or typeAheadSql is defined, but can be turned off with typeAheadPedantic=0.

  • Form.parameter or FormElement.parameter:
    • typeAheadPedantic=0

Prefetch

After ‘form load’ with an existing record, the user expects to see the previous saved data. In case there is an id to value translation, the value does not exist in the database, instead it has to be fetched again dynamically. A precise LDAP or SQL query has to be defined to force this:

  • Form.parameter or FormElement.parameter:
    • typeAheadLdapSearchPrefetch = (mail=?)
    • typeAheadSqlPrefetch = SELECT firstName, ‘ ‘, lastName FROM Person WHERE id = ?

This situation also applies in pedantic mode to verify the user input after each change.

PerToken

Sometimes a LDAP server only provides attributes like ‘sn’ and ‘givenName’, but not ‘displayName’ or another practical combination of multiple attributes - than it is difficult to search for ‘firstname’ and (=human AND) ‘lastname’. E.g. ‘John Doe’, results to search like (|(sn=*John Doe*)(givenName=*John Doe*)) which will be probably always be empty. Instead, the user input has to be split in token and the search string has to repeated for every token.

  • Form.parameter or FormElement.parameter:
    • typeAheadLdapSearchPerToken - no value needed.

This will repeat the search string per token.

E.g.:

User search string: X Y
Ldap search string: (|(a=*?*)(b=*?*))

Result: (& (|(a=*X*)(b=*X*)) (|(a=*Y*)(b=*Y*))

Attention: this option is only useful in specific environments. Only use it, if it is really needed. The query becomes much more cpu / IO intensive.

Fill STORE LDAP (FSL)

Before processing a FormElement, an optional configured FSL-action loads one record from a LDAP directory and stores the named attributes in STORE_LDAP. If the LDAP search query selects more than one record, only the first record is processed. The attributes names always becomes lowercase (PHP implentation detail on get_ldap_entries()) in the store. To make accessing STORE_LDAP easily, the keys are implemented case insensitive for this specific store. FLS is triggered during Form-…

  • load,
  • dynamic update,
  • save.

The FLS happens before the FormElement processing starts. Therefore the fetched LDAP data (specified by ldapAttributes), are available via {{<attributename>:L:allbut:s}} during the regular FormElement processing. Take care to specify a sanitize class and optional escaping on further processing of those data.

Also, the STORE LDAP remains filled, during the whole form processing time. E.g. if the values are needed for a person name and email, it’s sufficient to fire one FSL on the first FormElement Action element, and use the same values during further FormElement Action Elements.

Important

LDAP access might slow down the Form processing on load, update or save! The timeout (default: 3 seconds) have to be multiplied by the number of accesses. E.g. a broken LDAP connection and 3 FormElements with FSL results to 9 seconds delay on save. Also be prepared not to receive the expected data.

  • FormElement.parameter.fillStoreLdap - activate the mode Fill S - no value is needed, the existence is sufficient.
  • Form.parameter or FormElement.parameter:
    • ldapServer = directory.example.com
    • ldapBaseDn = ou=Addressbook,dc=example,dc=com
    • typeAheadLdapSearch = (|(cn=*?*)(mail=*?*))
    • ldapAttributes = givenName, sn, telephoneNumber, email
    • ldapSearch = (mail={{email:F0:alnumx:l}})
    • Optional: ldapUseBindCredentials = 1

After filling the store, access the content via {{<attributename>:L:allbut:s}}.