LDAP.rst 14.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.. ==================================================
.. ==================================================
.. ==================================================
.. 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 <http://getbootstrap.com/>`_
19
.. Internal Link: :ref:`downloadButton` (default url text) or :ref:`download Button<downloadButton>` (explicit url text)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
.. 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 |
+=============================+==================================+=====================================================================+======+=============+==========+
Carsten  Rose's avatar
Carsten Rose committed
56
| ldapServer                  | ldaps://directory.example.com:636| Hostname.                                                           | x    | x           | TA, FSL  |
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
+-----------------------------+----------------------------------+---------------------------------------------------------------------+------+-------------+----------+
| 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*:

Carsten  Rose's avatar
Carsten Rose committed
109
  * *ldapServer* = `ldaps://directory.example.com:636`
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  * *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 `{{<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*:

Carsten  Rose's avatar
Carsten Rose committed
217
  * *ldapServer* = `ldaps://directory.example.com:636`
218
219
220
221
222
223
224
  * *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}}`.