.. ==================================================
.. ==================================================
.. ==================================================
.. Header hierarchy
.. ==
.. --
.. ^^
.. ""
.. ;;
.. ,,
..
.. --------------------------------------------used to the update the records specified ------
.. Best Practice T3 reST: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/CheatSheet.html
.. Reference: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/Index.html
.. Italic *italic*
.. Bold **bold**
.. Code ``text``
.. External Links: `Bootstrap `_
.. Internal Link: :ref:`downloadButton` (default url text) or :ref:`download Button` (explicit url text)
.. Add Images: .. image:: ./Images/a4.jpg
..
..
.. Admonitions
.. .. note:: .. important:: .. tip:: .. warning::
.. Color: (blue) (orange) (green) (red)
..
.. Definition:
.. some text becomes strong (only one line)
.. description has to indented
.. -*- coding: utf-8 -*- with BOM.
.. include:: Includes.txt
.. _LDAP:
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 | ldaps://directory.example.com:636| Hostname. | 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 :ref:`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 | x | x | TA |
| | | the individual tokens | | | |
+-----------------------------+----------------------------------+---------------------------------------------------------------------+------+-------------+----------+
| 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
:ref:`config-qfq-php`.
.. _LDAP_Typeahead:
Typeahead (TA) - LDAP
---------------------
See also :ref:`input-typeahead`
*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* = `ldaps://directory.example.com:636`
* *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_LDAP_STORE:
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 `{{: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* = `ldaps://directory.example.com:636`
* *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 `{{:L:allbut:s}}`.