.. ================================================== .. ================================================== .. ================================================== .. 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}}`.