xref: /netbsd-src/external/bsd/openldap/dist/doc/guide/admin/access-control.sdf (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1# OpenLDAP: pkg/openldap-guide/admin/access-control.sdf,v 1.3.2.7 2009/06/27 17:55:38 quanah Exp
2# Copyright 1999-2009 The OpenLDAP Foundation, All Rights Reserved.
3# COPYING RESTRICTIONS APPLY, see COPYRIGHT.
4
5H1: Access Control
6
7H2: Introduction
8
9As the directory gets populated with more and more data of varying sensitivity,
10controlling the kinds of access granted to the directory becomes more and more
11critical. For instance, the directory may contain data of a confidential nature
12that you may need to protect by contract or by law. Or, if using the directory
13to control access to other services, inappropriate access to the directory may
14create avenues of attack to your sites security that result in devastating
15damage to your assets.
16
17Access to your directory can be configured via two methods, the first using
18{{SECT:The slapd Configuration File}} and the second using the {{slapd-config}}(5)
19format ({{SECT:Configuring slapd}}).
20
21The default access control policy is allow read by all clients. Regardless of
22what access control policy is defined, the {{rootdn}} is always allowed full
23rights (i.e. auth, search, compare, read and write) on everything and anything.
24
25As a consequence, it's useless (and results in a performance penalty) to explicitly
26list the {{rootdn}} among the {{<by>}} clauses.
27
28The following sections will describe Access Control Lists in more details and
29follow with some examples and recommendations.
30
31H2: Access Control via Static Configuration
32
33Access to entries and attributes is controlled by the
34access configuration file directive. The general form of an
35access line is:
36
37>    <access directive> ::= access to <what>
38>        [by <who> [<access>] [<control>] ]+
39>    <what> ::= * |
40>        [dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
41>        [filter=<ldapfilter>] [attrs=<attrlist>]
42>    <basic-style> ::= regex | exact
43>    <scope-style> ::= base | one | subtree | children
44>    <attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist>
45>    <attr> ::= <attrname> | entry | children
46>    <who> ::= * | [anonymous | users | self
47>            | dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
48>        [dnattr=<attrname>]
49>        [group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>]
50>        [peername[.<basic-style>]=<regex>]
51>        [sockname[.<basic-style>]=<regex>]
52>        [domain[.<basic-style>]=<regex>]
53>        [sockurl[.<basic-style>]=<regex>]
54>        [set=<setspec>]
55>        [aci=<attrname>]
56>    <access> ::= [self]{<level>|<priv>}
57>    <level> ::= none | disclose | auth | compare | search | read | write | manage
58>    <priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+
59>    <control> ::= [stop | continue | break]
60
61where the <what> part selects the entries and/or attributes to which
62the access applies, the {{EX:<who>}} part specifies which entities
63are granted access, and the {{EX:<access>}} part specifies the
64access granted. Multiple {{EX:<who> <access> <control>}} triplets
65are supported, allowing many entities to be granted different access
66to the same set of entries and attributes. Not all of these access
67control options are described here; for more details see the
68{{slapd.access}}(5) man page.
69
70
71H3: What to control access to
72
73The <what> part of an access specification determines the entries
74and attributes to which the access control applies.  Entries are
75commonly selected in two ways: by DN and by filter.  The following
76qualifiers select entries by DN:
77
78>    to *
79>    to dn[.<basic-style>]=<regex>
80>    to dn.<scope-style>=<DN>
81
82The first form is used to select all entries.  The second form may
83be used to select entries by matching a regular expression against
84the target entry's {{normalized DN}}.   (The second form is not
85discussed further in this document.)  The third form is used to
86select entries which are within the requested scope of DN.  The
87<DN> is a string representation of the Distinguished Name, as
88described in {{REF:RFC4514}}.
89
90The scope can be either {{EX:base}}, {{EX:one}}, {{EX:subtree}},
91or {{EX:children}}.  Where {{EX:base}} matches only the entry with
92provided DN, {{EX:one}} matches the entries whose parent is the
93provided DN, {{EX:subtree}} matches all entries in the subtree whose
94root is the provided DN, and {{EX:children}} matches all entries
95under the DN (but not the entry named by the DN).
96
97For example, if the directory contained entries named:
98
99>    0: o=suffix
100>    1: cn=Manager,o=suffix
101>    2: ou=people,o=suffix
102>    3: uid=kdz,ou=people,o=suffix
103>    4: cn=addresses,uid=kdz,ou=people,o=suffix
104>    5: uid=hyc,ou=people,o=suffix
105
106\Then:
107. {{EX:dn.base="ou=people,o=suffix"}} match 2;
108. {{EX:dn.one="ou=people,o=suffix"}} match 3, and 5;
109. {{EX:dn.subtree="ou=people,o=suffix"}} match 2, 3, 4, and 5; and
110. {{EX:dn.children="ou=people,o=suffix"}} match 3, 4, and 5.
111
112
113Entries may also be selected using a filter:
114
115>    to filter=<ldap filter>
116
117where <ldap filter> is a string representation of an LDAP
118search filter, as described in {{REF:RFC4515}}.  For example:
119
120>    to filter=(objectClass=person)
121
122Note that entries may be selected by both DN and filter by
123including both qualifiers in the <what> clause.
124
125>    to dn.one="ou=people,o=suffix" filter=(objectClass=person)
126
127Attributes within an entry are selected by including a comma-separated
128list of attribute names in the <what> selector:
129
130>    attrs=<attribute list>
131
132A specific value of an attribute is selected by using a single
133attribute name and also using a value selector:
134
135>    attrs=<attribute> val[.<style>]=<regex>
136
137There are two special {{pseudo}} attributes {{EX:entry}} and
138{{EX:children}}.  To read (and hence return) a target entry, the
139subject must have {{EX:read}} access to the target's {{entry}}
140attribute.  To perform a search, the subject must have
141{{EX:search}} access to the search base's {{entry}} attribute.
142To add or delete an entry, the subject must have
143{{EX:write}} access to the entry's {{EX:entry}} attribute AND must
144have {{EX:write}} access to the entry's parent's {{EX:children}}
145attribute.  To rename an entry, the subject must have {{EX:write}}
146access to entry's {{EX:entry}} attribute AND have {{EX:write}}
147access to both the old parent's and new parent's {{EX:children}}
148attributes.  The complete examples at the end of this section should
149help clear things up.
150
151Lastly, there is a special entry selector {{EX:"*"}} that is used to
152select any entry.  It is used when no other {{EX:<what>}}
153selector has been provided.  It's equivalent to "{{EX:dn=.*}}"
154
155
156H3: Who to grant access to
157
158The <who> part identifies the entity or entities being granted
159access. Note that access is granted to "entities" not "entries."
160The following table summarizes entity specifiers:
161
162!block table; align=Center; coltags="EX,N"; \
163    title="Table 6.3: Access Entity Specifiers"
164Specifier|Entities
165*|All, including anonymous and authenticated users
166anonymous|Anonymous (non-authenticated) users
167users|Authenticated users
168self|User associated with target entry
169dn[.<basic-style>]=<regex>|Users matching a regular expression
170dn.<scope-style>=<DN>|Users within scope of a DN
171!endblock
172
173The DN specifier behaves much like <what> clause DN specifiers.
174
175Other control factors are also supported.  For example, a {{EX:<who>}}
176can be restricted by an entry listed in a DN-valued attribute in
177the entry to which the access applies:
178
179>    dnattr=<dn-valued attribute name>
180
181The dnattr specification is used to give access to an entry
182whose DN is listed in an attribute of the entry (e.g., give
183access to a group entry to whoever is listed as the owner of
184the group entry).
185
186Some factors may not be appropriate in all environments (or any).
187For example, the domain factor relies on IP to domain name lookups.
188As these can easily be spoofed, the domain factor should be avoided.
189
190
191H3: The access to grant
192
193The kind of <access> granted can be one of the following:
194
195!block table; colaligns="LRL"; coltags="EX,EX,N"; align=Center; \
196    title="Table 6.4: Access Levels"
197Level        Privileges    Description
198none        =0             no access
199disclose    =d             needed for information disclosure on error
200auth        =dx            needed to authenticate (bind)
201compare     =cdx           needed to compare
202search      =scdx          needed to apply search filters
203read        =rscdx         needed to read search results
204write       =wrscdx        needed to modify/rename
205manage      =mwrscdx       needed to manage
206!endblock
207
208Each level implies all lower levels of access. So, for example,
209granting someone {{EX:write}} access to an entry also grants them
210{{EX:read}}, {{EX:search}}, {{EX:compare}}, {{EX:auth}} and
211{{EX:disclose}} access.  However, one may use the privileges specifier
212to grant specific permissions.
213
214
215H3: Access Control Evaluation
216
217When evaluating whether some requester should be given access to
218an entry and/or attribute, slapd compares the entry and/or attribute
219to the {{EX:<what>}} selectors given in the configuration file.
220For each entry, access controls provided in the database which holds
221the entry (or the global access directives if not held in any database) apply
222first, followed by the global access directives. However, when dealing with
223an access list, because the global access list is effectively appended
224to each per-database list, if the resulting list is non-empty then the
225access list will end with an implicit {{EX:access to * by * none}} directive.
226If there are no access directives applicable to a backend, then a default
227read is used.
228
229Within this
230priority, access directives are examined in the order in which they
231appear in the config file.  Slapd stops with the first {{EX:<what>}}
232selector that matches the entry and/or attribute. The corresponding
233access directive is the one slapd will use to evaluate access.
234
235Next, slapd compares the entity requesting access to the {{EX:<who>}}
236selectors within the access directive selected above in the order
237in which they appear. It stops with the first {{EX:<who>}} selector
238that matches the requester. This determines the access the entity
239requesting access has to the entry and/or attribute.
240
241Finally, slapd compares the access granted in the selected
242{{EX:<access>}} clause to the access requested by the client. If
243it allows greater or equal access, access is granted. Otherwise,
244access is denied.
245
246The order of evaluation of access directives makes their placement
247in the configuration file important. If one access directive is
248more specific than another in terms of the entries it selects, it
249should appear first in the config file. Similarly, if one {{EX:<who>}}
250selector is more specific than another it should come first in the
251access directive. The access control examples given below should
252help make this clear.
253
254
255
256H3: Access Control Examples
257
258The access control facility described above is quite powerful.  This
259section shows some examples of its use for descriptive purposes.
260
261A simple example:
262
263>    access to * by * read
264
265This access directive grants read access to everyone.
266
267>    access to *
268>        by self write
269>        by anonymous auth
270>        by * read
271
272This directive allows the user to modify their entry, allows anonymous
273to authentication against these entries, and allows all others to
274read these entries.  Note that only the first {{EX:by <who>}} clause
275which matches applies.  Hence, the anonymous users are granted
276{{EX:auth}}, not {{EX:read}}.  The last clause could just as well
277have been "{{EX:by users read}}".
278
279It is often desirable to restrict operations based upon the level
280of protection in place.  The following shows how security strength
281factors (SSF) can be used.
282
283>    access to *
284>        by ssf=128 self write
285>        by ssf=64 anonymous auth
286>        by ssf=64 users read
287
288This directive allows users to modify their own entries if security
289protections have of strength 128 or better have been established,
290allows authentication access to anonymous users, and read access
291when 64 or better security protections have been established.  If
292client has not establish sufficient security protections, the
293implicit {{EX:by * none}} clause would be applied.
294
295The following example shows the use of a style specifiers to select
296the entries by DN in two access directives where ordering is
297significant.
298
299>    access to dn.children="dc=example,dc=com"
300>         by * search
301>    access to dn.children="dc=com"
302>         by * read
303
304Read access is granted to entries under the {{EX:dc=com}} subtree,
305except for those entries under the {{EX:dc=example,dc=com}} subtree,
306to which search access is granted.  No access is granted to
307{{EX:dc=com}} as neither access directive matches this DN.  If the
308order of these access directives was reversed, the trailing directive
309would never be reached, since all entries under {{EX:dc=example,dc=com}}
310are also under {{EX:dc=com}} entries.
311
312Also note that if no {{EX:access to}} directive matches or no {{EX:by
313<who>}} clause, {{B:access is denied}}.  That is, every {{EX:access
314to}} directive ends with an implicit {{EX:by * none}} clause. When dealing
315with an access list, because the global access list is effectively appended
316to each per-database list, if the resulting list is non-empty then the access
317list will end with an implicit {{EX:access to * by * none}} directive. If
318there are no access directives applicable to a backend, then a default read is
319used.
320
321The next example again shows the importance of ordering, both of
322the access directives and the {{EX:by <who>}} clauses.  It also
323shows the use of an attribute selector to grant access to a specific
324attribute and various {{EX:<who>}} selectors.
325
326>    access to dn.subtree="dc=example,dc=com" attrs=homePhone
327>        by self write
328>        by dn.children="dc=example,dc=com" search
329>        by peername.regex=IP:10\..+ read
330>    access to dn.subtree="dc=example,dc=com"
331>        by self write
332>        by dn.children="dc=example,dc=com" search
333>        by anonymous auth
334
335This example applies to entries in the "{{EX:dc=example,dc=com}}"
336subtree. To all attributes except {{EX:homePhone}}, an entry can
337write to itself, entries under {{EX:example.com}} entries can search
338by them, anybody else has no access (implicit {{EX:by * none}})
339excepting for authentication/authorization (which is always done
340anonymously).  The {{EX:homePhone}} attribute is writable by the
341entry, searchable by entries under {{EX:example.com}}, readable by
342clients connecting from network 10, and otherwise not readable
343(implicit {{EX:by * none}}).  All other access is denied by the
344implicit {{EX:access to * by * none}}.
345
346Sometimes it is useful to permit a particular DN to add or
347remove itself from an attribute. For example, if you would like to
348create a group and allow people to add and remove only
349their own DN from the member attribute, you could accomplish
350it with an access directive like this:
351
352>    access to attrs=member,entry
353>         by dnattr=member selfwrite
354
355The dnattr {{EX:<who>}} selector says that the access applies to
356entries listed in the {{EX:member}} attribute. The {{EX:selfwrite}} access
357selector says that such members can only add or delete their
358own DN from the attribute, not other values. The addition of
359the entry attribute is required because access to the entry is
360required to access any of the entry's attributes.
361
362!if 0
363For more details on how to use the {{EX:access}} directive,
364consult the {{Advanced Access Control}} chapter.
365!endif
366
367
368H2: Access Control via Dynamic Configuration
369
370Access to slapd entries and attributes is controlled by the
371olcAccess attribute, whose values are a sequence of access directives.
372The general form of the olcAccess configuration is:
373
374>    olcAccess: <access directive>
375>    <access directive> ::= to <what>
376>        [by <who> [<access>] [<control>] ]+
377>    <what> ::= * |
378>        [dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
379>        [filter=<ldapfilter>] [attrs=<attrlist>]
380>    <basic-style> ::= regex | exact
381>    <scope-style> ::= base | one | subtree | children
382>    <attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist>
383>    <attr> ::= <attrname> | entry | children
384>    <who> ::= * | [anonymous | users | self
385>            | dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
386>        [dnattr=<attrname>]
387>        [group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>]
388>        [peername[.<basic-style>]=<regex>]
389>        [sockname[.<basic-style>]=<regex>]
390>        [domain[.<basic-style>]=<regex>]
391>        [sockurl[.<basic-style>]=<regex>]
392>        [set=<setspec>]
393>        [aci=<attrname>]
394>    <access> ::= [self]{<level>|<priv>}
395>    <level> ::= none | disclose | auth | compare | search | read | write | manage
396>    <priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+
397>    <control> ::= [stop | continue | break]
398
399where the <what> part selects the entries and/or attributes to which
400the access applies, the {{EX:<who>}} part specifies which entities
401are granted access, and the {{EX:<access>}} part specifies the
402access granted. Multiple {{EX:<who> <access> <control>}} triplets
403are supported, allowing many entities to be granted different access
404to the same set of entries and attributes. Not all of these access
405control options are described here; for more details see the
406{{slapd.access}}(5) man page.
407
408
409H3: What to control access to
410
411The <what> part of an access specification determines the entries
412and attributes to which the access control applies.  Entries are
413commonly selected in two ways: by DN and by filter.  The following
414qualifiers select entries by DN:
415
416>    to *
417>    to dn[.<basic-style>]=<regex>
418>    to dn.<scope-style>=<DN>
419
420The first form is used to select all entries.  The second form may
421be used to select entries by matching a regular expression against
422the target entry's {{normalized DN}}.   (The second form is not
423discussed further in this document.)  The third form is used to
424select entries which are within the requested scope of DN.  The
425<DN> is a string representation of the Distinguished Name, as
426described in {{REF:RFC4514}}.
427
428The scope can be either {{EX:base}}, {{EX:one}}, {{EX:subtree}},
429or {{EX:children}}.  Where {{EX:base}} matches only the entry with
430provided DN, {{EX:one}} matches the entries whose parent is the
431provided DN, {{EX:subtree}} matches all entries in the subtree whose
432root is the provided DN, and {{EX:children}} matches all entries
433under the DN (but not the entry named by the DN).
434
435For example, if the directory contained entries named:
436
437>    0: o=suffix
438>    1: cn=Manager,o=suffix
439>    2: ou=people,o=suffix
440>    3: uid=kdz,ou=people,o=suffix
441>    4: cn=addresses,uid=kdz,ou=people,o=suffix
442>    5: uid=hyc,ou=people,o=suffix
443
444\Then:
445. {{EX:dn.base="ou=people,o=suffix"}} match 2;
446. {{EX:dn.one="ou=people,o=suffix"}} match 3, and 5;
447. {{EX:dn.subtree="ou=people,o=suffix"}} match 2, 3, 4, and 5; and
448. {{EX:dn.children="ou=people,o=suffix"}} match 3, 4, and 5.
449
450
451Entries may also be selected using a filter:
452
453>    to filter=<ldap filter>
454
455where <ldap filter> is a string representation of an LDAP
456search filter, as described in {{REF:RFC4515}}.  For example:
457
458>    to filter=(objectClass=person)
459
460Note that entries may be selected by both DN and filter by
461including both qualifiers in the <what> clause.
462
463>    to dn.one="ou=people,o=suffix" filter=(objectClass=person)
464
465Attributes within an entry are selected by including a comma-separated
466list of attribute names in the <what> selector:
467
468>    attrs=<attribute list>
469
470A specific value of an attribute is selected by using a single
471attribute name and also using a value selector:
472
473>    attrs=<attribute> val[.<style>]=<regex>
474
475There are two special {{pseudo}} attributes {{EX:entry}} and
476{{EX:children}}.  To read (and hence return) a target entry, the
477subject must have {{EX:read}} access to the target's {{entry}}
478attribute.  To perform a search, the subject must have
479{{EX:search}} access to the search base's {{entry}} attribute.
480To add or delete an entry, the subject must have
481{{EX:write}} access to the entry's {{EX:entry}} attribute AND must
482have {{EX:write}} access to the entry's parent's {{EX:children}}
483attribute.  To rename an entry, the subject must have {{EX:write}}
484access to entry's {{EX:entry}} attribute AND have {{EX:write}}
485access to both the old parent's and new parent's {{EX:children}}
486attributes.  The complete examples at the end of this section should
487help clear things up.
488
489Lastly, there is a special entry selector {{EX:"*"}} that is used to
490select any entry.  It is used when no other {{EX:<what>}}
491selector has been provided.  It's equivalent to "{{EX:dn=.*}}"
492
493
494H3: Who to grant access to
495
496The <who> part identifies the entity or entities being granted
497access. Note that access is granted to "entities" not "entries."
498The following table summarizes entity specifiers:
499
500!block table; align=Center; coltags="EX,N"; \
501    title="Table 5.3: Access Entity Specifiers"
502Specifier|Entities
503*|All, including anonymous and authenticated users
504anonymous|Anonymous (non-authenticated) users
505users|Authenticated users
506self|User associated with target entry
507dn[.<basic-style>]=<regex>|Users matching a regular expression
508dn.<scope-style>=<DN>|Users within scope of a DN
509!endblock
510
511The DN specifier behaves much like <what> clause DN specifiers.
512
513Other control factors are also supported.  For example, a {{EX:<who>}}
514can be restricted by an entry listed in a DN-valued attribute in
515the entry to which the access applies:
516
517>    dnattr=<dn-valued attribute name>
518
519The dnattr specification is used to give access to an entry
520whose DN is listed in an attribute of the entry (e.g., give
521access to a group entry to whoever is listed as the owner of
522the group entry).
523
524Some factors may not be appropriate in all environments (or any).
525For example, the domain factor relies on IP to domain name lookups.
526As these can easily be spoofed, the domain factor should be avoided.
527
528
529H3: The access to grant
530
531The kind of <access> granted can be one of the following:
532
533!block table; colaligns="LRL"; coltags="EX,EX,N"; align=Center; \
534    title="Table 5.4: Access Levels"
535Level        Privileges    Description
536none         =0            no access
537disclose     =d            needed for information disclosure on error
538auth         =dx           needed to authenticate (bind)
539compare      =cdx          needed to compare
540search       =scdx         needed to apply search filters
541read         =rscdx        needed to read search results
542write        =wrscdx       needed to modify/rename
543manage       =mwrscdx      needed to manage
544!endblock
545
546Each level implies all lower levels of access. So, for example,
547granting someone {{EX:write}} access to an entry also grants them
548{{EX:read}}, {{EX:search}}, {{EX:compare}}, {{EX:auth}} and
549{{EX:disclose}} access.  However, one may use the privileges specifier
550to grant specific permissions.
551
552
553H3: Access Control Evaluation
554
555When evaluating whether some requester should be given access to
556an entry and/or attribute, slapd compares the entry and/or attribute
557to the {{EX:<what>}} selectors given in the configuration.  For
558each entry, access controls provided in the database which holds
559the entry (or the global access directives if not held in any database) apply
560first, followed by the global access directives (which are held in
561the {{EX:frontend}} database definition). However, when dealing with
562an access list, because the global access list is effectively appended
563to each per-database list, if the resulting list is non-empty then the
564access list will end with an implicit {{EX:access to * by * none}} directive.
565If there are no access directives applicable to a backend, then a default
566read is used.
567
568Within this priority,
569access directives are examined in the order in which they appear
570in the configuration attribute.  Slapd stops with the first
571{{EX:<what>}} selector that matches the entry and/or attribute. The
572corresponding access directive is the one slapd will use to evaluate
573access.
574
575Next, slapd compares the entity requesting access to the {{EX:<who>}}
576selectors within the access directive selected above in the order
577in which they appear. It stops with the first {{EX:<who>}} selector
578that matches the requester. This determines the access the entity
579requesting access has to the entry and/or attribute.
580
581Finally, slapd compares the access granted in the selected
582{{EX:<access>}} clause to the access requested by the client. If
583it allows greater or equal access, access is granted. Otherwise,
584access is denied.
585
586The order of evaluation of access directives makes their placement
587in the configuration file important. If one access directive is
588more specific than another in terms of the entries it selects, it
589should appear first in the configuration. Similarly, if one {{EX:<who>}}
590selector is more specific than another it should come first in the
591access directive. The access control examples given below should
592help make this clear.
593
594
595
596H3: Access Control Examples
597
598The access control facility described above is quite powerful.  This
599section shows some examples of its use for descriptive purposes.
600
601A simple example:
602
603>    olcAccess: to * by * read
604
605This access directive grants read access to everyone.
606
607>    olcAccess: to *
608>        by self write
609>        by anonymous auth
610>        by * read
611
612This directive allows the user to modify their entry, allows anonymous
613to authenticate against these entries, and allows all others to
614read these entries.  Note that only the first {{EX:by <who>}} clause
615which matches applies.  Hence, the anonymous users are granted
616{{EX:auth}}, not {{EX:read}}.  The last clause could just as well
617have been "{{EX:by users read}}".
618
619It is often desirable to restrict operations based upon the level
620of protection in place.  The following shows how security strength
621factors (SSF) can be used.
622
623>    olcAccess: to *
624>        by ssf=128 self write
625>        by ssf=64 anonymous auth
626>        by ssf=64 users read
627
628This directive allows users to modify their own entries if security
629protections of strength 128 or better have been established,
630allows authentication access to anonymous users, and read access
631when strength 64 or better security protections have been established.  If
632the client has not establish sufficient security protections, the
633implicit {{EX:by * none}} clause would be applied.
634
635The following example shows the use of style specifiers to select
636the entries by DN in two access directives where ordering is
637significant.
638
639>    olcAccess: to dn.children="dc=example,dc=com"
640>         by * search
641>    olcAccess: to dn.children="dc=com"
642>         by * read
643
644Read access is granted to entries under the {{EX:dc=com}} subtree,
645except for those entries under the {{EX:dc=example,dc=com}} subtree,
646to which search access is granted.  No access is granted to
647{{EX:dc=com}} as neither access directive matches this DN.  If the
648order of these access directives was reversed, the trailing directive
649would never be reached, since all entries under {{EX:dc=example,dc=com}}
650are also under {{EX:dc=com}} entries.
651
652Also note that if no {{EX:olcAccess: to}} directive matches or no {{EX:by
653<who>}} clause, {{B:access is denied}}.  When dealing with an access list,
654because the global access list is effectively appended to each per-database
655list, if the resulting list is non-empty then the access list will end with
656an implicit {{EX:access to * by * none}} directive. If there are no access
657directives applicable to a backend, then a default read is used.
658
659The next example again shows the importance of ordering, both of
660the access directives and the {{EX:by <who>}} clauses.  It also
661shows the use of an attribute selector to grant access to a specific
662attribute and various {{EX:<who>}} selectors.
663
664>    olcAccess: to dn.subtree="dc=example,dc=com" attrs=homePhone
665>        by self write
666>        by dn.children=dc=example,dc=com" search
667>        by peername.regex=IP:10\..+ read
668>    olcAccess: to dn.subtree="dc=example,dc=com"
669>        by self write
670>        by dn.children="dc=example,dc=com" search
671>        by anonymous auth
672
673This example applies to entries in the "{{EX:dc=example,dc=com}}"
674subtree. To all attributes except {{EX:homePhone}}, an entry can
675write to itself, entries under {{EX:example.com}} entries can search
676by them, anybody else has no access (implicit {{EX:by * none}})
677excepting for authentication/authorization (which is always done
678anonymously).  The {{EX:homePhone}} attribute is writable by the
679entry, searchable by entries under {{EX:example.com}}, readable by
680clients connecting from network 10, and otherwise not readable
681(implicit {{EX:by * none}}).  All other access is denied by the
682implicit {{EX:access to * by * none}}.
683
684Sometimes it is useful to permit a particular DN to add or
685remove itself from an attribute. For example, if you would like to
686create a group and allow people to add and remove only
687their own DN from the member attribute, you could accomplish
688it with an access directive like this:
689
690>    olcAccess: to attrs=member,entry
691>         by dnattr=member selfwrite
692
693The dnattr {{EX:<who>}} selector says that the access applies to
694entries listed in the {{EX:member}} attribute. The {{EX:selfwrite}} access
695selector says that such members can only add or delete their
696own DN from the attribute, not other values. The addition of
697the entry attribute is required because access to the entry is
698required to access any of the entry's attributes.
699
700
701
702H3: Access Control Ordering
703
704Since the ordering of {{EX:olcAccess}} directives is essential to their
705proper evaluation, but LDAP attributes normally do not preserve the
706ordering of their values, OpenLDAP uses a custom schema extension to
707maintain a fixed ordering of these values. This ordering is maintained
708by prepending a {{EX:"{X}"}} numeric index to each value, similarly to
709the approach used for ordering the configuration entries. These index
710tags are maintained automatically by slapd and do not need to be specified
711when originally defining the values. For example, when you create the
712settings
713
714>    olcAccess: to attrs=member,entry
715>         by dnattr=member selfwrite
716>    olcAccess: to dn.children="dc=example,dc=com"
717>         by * search
718>    olcAccess: to dn.children="dc=com"
719>         by * read
720
721when you read them back using slapcat or ldapsearch they will contain
722
723>    olcAccess: {0}to attrs=member,entry
724>         by dnattr=member selfwrite
725>    olcAccess: {1}to dn.children="dc=example,dc=com"
726>         by * search
727>    olcAccess: {2}to dn.children="dc=com"
728>         by * read
729
730The numeric index may be used to specify a particular value to change
731when using ldapmodify to edit the access rules. This index can be used
732instead of (or in addition to) the actual access value. Using this
733numeric index is very helpful when multiple access rules are being managed.
734
735For example, if we needed to change the second rule above to grant
736write access instead of search, we could try this LDIF:
737
738>    changetype: modify
739>    delete: olcAccess
740>    olcAccess: to dn.children="dc=example,dc=com" by * search
741>    -
742>    add: olcAccess
743>    olcAccess: to dn.children="dc=example,dc=com" by * write
744>    -
745
746But this example {{B:will not}} guarantee that the existing values remain in
747their original order, so it will most likely yield a broken security
748configuration. Instead, the numeric index should be used:
749
750>    changetype: modify
751>    delete: olcAccess
752>    olcAccess: {1}
753>    -
754>    add: olcAccess
755>    olcAccess: {1}to dn.children="dc=example,dc=com" by * write
756>    -
757
758This example deletes whatever rule is in value #1 of the {{EX:olcAccess}}
759attribute (regardless of its value) and adds a new value that is
760explicitly inserted as value #1. The result will be
761
762>    olcAccess: {0}to attrs=member,entry
763>         by dnattr=member selfwrite
764>    olcAccess: {1}to dn.children="dc=example,dc=com"
765>         by * write
766>    olcAccess: {2}to dn.children="dc=com"
767>         by * read
768
769which is exactly what was intended.
770
771!if 0
772For more details on how to use the {{EX:access}} directive,
773consult the {{Advanced Access Control}} chapter.
774!endif
775
776
777H2: Access Control Common Examples
778
779H3: Basic ACLs
780
781Generally one should start with some basic ACLs such as:
782
783>    access to attr=userPassword
784>        by self =xw
785>        by anonymous auth
786>        by * none
787>
788>
789>      access to *
790>        by self write
791>        by users read
792>        by * none
793
794The first ACL allows users to update (but not read) their passwords, anonymous
795users to authenticate against this attribute, and (implicitly) denying all
796access to others.
797
798The second ACL allows users full access to their entry, authenticated users read
799access to anything, and (implicitly) denying all access to others (in this case,
800anonymous users).
801
802
803H3: Matching Anonymous and Authenticated users
804
805An anonymous user has a empty DN. While the {{dn.exact=""}} or {{dn.regex="^$"}}
806 could be used, {{slapd}}(8)) offers an anonymous shorthand which should be
807used instead.
808
809>    access to *
810>      by anonymous none
811>      by * read
812
813denies all access to anonymous users while granting others read.
814
815Authenticated users have a subject DN. While {{dn.regex=".+"}} will match any
816authenticated user, OpenLDAP provides the users short hand which should be used
817instead.
818
819>    access to *
820>      by users read
821>      by * none
822
823This ACL grants read permissions to authenticated users while denying others
824(i.e.: anonymous users).
825
826
827H3: Controlling rootdn access
828
829You could specify the {{rootdn}} in {{slapd.conf}}(5) or {[slapd.d}} without
830specifying a {{rootpw}}. Then you have to add an actual directory entry with
831the same dn, e.g.:
832
833>    dn: cn=Manager,o=MyOrganization
834>    cn: Manager
835>    sn: Manager
836>    objectClass: person
837>    objectClass: top
838>    userPassword: {SSHA}someSSHAdata
839
840Then binding as the {{rootdn}} will require a regular bind to that DN, which
841in turn requires auth access to that entry's DN and {{userPassword}}, and this
842can be restricted via ACLs. E.g.:
843
844>    access to dn.base="cn=Manager,o=MyOrganization"
845>      by peername.regex=127\.0\.0\.1 auth
846>      by peername.regex=192\.168\.0\..* auth
847>      by users none
848>      by * none
849
850The ACLs above will only allow binding using rootdn from localhost and
851192.168.0.0/24.
852
853
854H3: Managing access with Groups
855
856There are a few ways to do this. One approach is illustrated here. Consider the
857following DIT layout:
858
859>    +-dc=example,dc=com
860>    +---cn=administrators,dc=example,dc=com
861>    +---cn=fred blogs,dc=example,dc=com
862
863and the following group object (in LDIF format):
864
865>    dn: cn=administrators,dc=example,dc=com
866>    cn: administrators of this region
867>    objectclass: groupOfNames  (important for the group acl feature)
868>    member: cn=fred blogs,dc=example,dc=com
869>    member: cn=somebody else,dc=example,dc=com
870
871One can then grant access to the members of this this group by adding appropriate
872{{by group}} clause to an access directive in {{slapd.conf}}(5). For instance,
873
874>    access to dn.children="dc=example,dc=com"
875>        by self write
876>        by group.exact="cn=Administrators,dc=example,dc=com" write
877>        by * auth
878
879Like by {[dn}} clauses, one can also use {{expand}} to expand the group name
880based upon the regular expression matching of the target, that is, the to {{dn.regex}}).
881For instance,
882
883>    access to dn.regex="(.+,)?ou=People,(dc=[^,]+,dc=[^,]+)$"
884>             attrs=children,entry,uid
885>        by group.expand="cn=Managers,$2" write
886>        by users read
887>        by * auth
888
889
890The above illustration assumed that the group members are to be found in the
891{{member}} attribute type of the {{groupOfNames}} object class. If you need to
892use a different group object and/or a different attribute type then use the
893following {{slapd.conf}}(5) (abbreviated) syntax:
894
895>    access to <what>
896>            by group/<objectclass>/<attributename>=<DN> <access>
897
898For example:
899
900>    access to *
901>      by group/organizationalRole/roleOccupant="cn=Administrator,dc=example,dc=com" write
902
903In this case, we have an ObjectClass {{organizationalRole}} which contains the
904administrator DN's in the {{roleOccupant}} attribute. For instance:
905
906>    dn: cn=Administrator,dc=example,dc=com
907>    cn: Administrator
908>    objectclass: organizationalRole
909>    roleOccupant: cn=Jane Doe,dc=example,dc=com
910
911Note: the specified member attribute type MUST be of DN or {{NameAndOptionalUID}} syntax,
912and the specified object class SHOULD allow the attribute type.
913
914Dynamic Groups are also supported in Access Control. Please see {{slapo-dynlist}}(5)
915and the {{SECT:Dynamic Lists}} overlay section.
916
917
918H3:  Granting access to a subset of attributes
919
920You can grant access to a set of attributes by specifying a list of attribute names
921in the ACL {{to}} clause. To be useful, you also need to grant access to the
922{{entry}} itself. Also note how {{children}} controls the ability to add, delete,
923and rename entries.
924
925>    # mail: self may write, authenticated users may read
926>    access to attrs=mail
927>      by self write
928>      by users read
929>      by * none
930>
931>    # cn, sn: self my write, all may read
932>    access to attrs=cn,sn
933>      by self write
934>      by * read
935>
936>    # immediate children: only self can add/delete entries under this entry
937>    access to attrs=children
938>      by self write
939>
940>    # entry itself: self may write, all may read
941>    access to attrs=entry
942>      by self write
943>      by * read
944>
945>    # other attributes: self may write, others have no access
946>    access to *
947>      by self write
948>      by * none
949
950ObjectClass names may also be specified in this list, which will affect
951all the attributes that are required and/or allowed by that {{objectClass}}.
952Actually, names in {{attrlist}} that are prefixed by {{@}} are directly treated
953as objectClass names. A name prefixed by {{!}} is also treated as an objectClass,
954but in this case the access rule affects the attributes that are not required
955nor allowed by that {{objectClass}}.
956
957
958H3: Allowing a user write to all entries below theirs
959
960For a setup where a user can write to its own record and to all of its children:
961
962>    access to dn.regex="(.+,)?(uid=[^,]+,o=Company)$"
963>       by dn.exact,expand="$2" write
964>       by anonymous auth
965
966(Add more examples for above)
967
968
969H3: Allowing entry creation
970
971Let's say, you have it like this:
972
973>        o=<basedn>
974>            ou=domains
975>                associatedDomain=<somedomain>
976>                    ou=users
977>                        uid=<someuserid>
978>                        uid=<someotheruserid>
979>                    ou=addressbooks
980>                        uid=<someuserid>
981>                            cn=<someone>
982>                            cn=<someoneelse>
983
984and, for another domain <someotherdomain>:
985
986>        o=<basedn>
987>            ou=domains
988>                associatedDomain=<someotherdomain>
989>                    ou=users
990>                        uid=<someuserid>
991>                        uid=<someotheruserid>
992>                    ou=addressbooks
993>                        uid=<someotheruserid>
994>                            cn=<someone>
995>                            cn=<someoneelse>
996
997then, if you wanted user {{uid=<someuserid>}} to {{B:ONLY}} create an entry
998for its own thing, you could write an ACL like this:
999
1000>    # this rule lets users of "associatedDomain=<matcheddomain>"
1001>    # write under "ou=addressbook,associatedDomain=<matcheddomain>,ou=domains,o=<basedn>",
1002>    # i.e. a user can write ANY entry below its domain's address book;
1003>    # this permission is necessary, but not sufficient, the next
1004>    # will restrict this permission further
1005>
1006>
1007>    access to dn.regex="^ou=addressbook,associatedDomain=([^,]+),ou=domains,o=<basedn>$" attrs=children
1008>            by dn.regex="^uid=([^,]+),ou=users,associatedDomain=$1,ou=domains,o=<basedn>$$" write
1009>            by * none
1010>
1011>
1012>    # Note that above the "by" clause needs a "regex" style to make sure
1013>    # it expands to a DN that starts with a "uid=<someuserid>" pattern
1014>    # while substituting the associatedDomain submatch from the "what" clause.
1015>
1016>
1017>    # This rule lets a user with "uid=<matcheduid>" of "<associatedDomain=matcheddomain>"
1018>    # write (i.e. add, modify, delete) the entry whose DN is exactly
1019>    # "uid=<matcheduid>,ou=addressbook,associatedDomain=<matcheddomain>,ou=domains,o=<basedn>"
1020>    # and ANY entry as subtree of it
1021>
1022>
1023>    access to dn.regex="^(.+,)?uid=([^,]+),ou=addressbook,associatedDomain=([^,]+),ou=domains,o=<basedn>$"
1024>            by dn.exact,expand="uid=$2,ou=users,associatedDomain=$3,ou=domains,o=<basedn>" write
1025>            by * none
1026>
1027>
1028>    # Note that above the "by" clause uses the "exact" style with the "expand"
1029>    # modifier because now the whole pattern can be rebuilt by means of the
1030>    # submatches from the "what" clause, so a "regex" compilation and evaluation
1031>    # is no longer required.
1032
1033
1034H3: Tips for using regular expressions in Access Control
1035
1036Always use {{dn.regex=<pattern>}} when you intend to use regular expression
1037matching. {{dn=<pattern>}} alone defaults to {{dn.exact<pattern>}}.
1038
1039Use {{(.+)}} instead of {{(.*)}} when you want at least one char to be matched.
1040{{(.*)}} matches the empty string as well.
1041
1042Don't use regular expressions for matches that can be done otherwise in a safer
1043and cheaper manner. Examples:
1044
1045>    dn.regex=".*dc=example,dc=com"
1046
1047is unsafe and expensive:
1048
1049    * unsafe because any string containing {{dc=example,dc=com }}will match,
1050not only those that end with the desired pattern; use {{.*dc=example,dc=com$}} instead.
1051    * unsafe also because it would allow any {{attributeType}} ending with {{dc}}
1052 as naming attribute for the first RDN in the string, e.g. a custom attributeType
1053{{mydc}} would match as well. If you really need a regular expression that allows
1054just {{dc=example,dc=com}} or any of its subtrees, use {{^(.+,)?dc=example,dc=com$}},
1055which means: anything to the left of dc=..., if any (the question mark after the
1056pattern within brackets), must end with a comma;
1057    * expensive because if you don't need submatches, you could use scoping styles, e.g.
1058
1059>    dn.subtree="dc=example,dc=com"
1060
1061to include {{dc=example,dc=com}} in the matching patterns,
1062
1063>    dn.children="dc=example,dc=com"
1064
1065to exclude {{dc=example,dc=com}} from the matching patterns, or
1066
1067>    dn.onelevel="dc=example,dc=com"
1068
1069to allow exactly one sublevel matches only.
1070
1071Always use {{^}} and {{$}} in regexes, whenever appropriate, because
1072{{ou=(.+),ou=(.+),ou=addressbooks,o=basedn}} will match
1073{{something=bla,ou=xxx,ou=yyy,ou=addressbooks,o=basedn,ou=addressbooks,o=basedn,dc=some,dc=org}}
1074
1075Always use {{([^,]+)}} to indicate exactly one RDN, because {{(.+)}} can
1076include any number of RDNs; e.g. {{ou=(.+),dc=example,dc=com}} will match
1077{{ou=My,o=Org,dc=example,dc=com}}, which might not be what you want.
1078
1079Never add the rootdn to the by clauses. ACLs are not even processed for operations
1080performed with rootdn identity (otherwise there would be no reason to define a
1081rootdn at all).
1082
1083Use shorthands. The user directive matches authenticated users and the anonymous
1084directive matches anonymous users.
1085
1086Don't use the {{dn.regex}} form for <by> clauses if all you need is scoping
1087and/or substring replacement; use scoping styles (e.g. {{exact}}, {{onelevel}},
1088{{children}} or {{subtree}}) and the style modifier expand to cause substring expansion.
1089
1090For instance,
1091
1092>    access to dn.regex=".+,dc=([^,]+),dc=([^,]+)$"
1093>      by dn.regex="^[^,],ou=Admin,dc=$1,dc=$2$$" write
1094
1095although correct, can be safely and efficiently replaced by
1096
1097>    access to dn.regex=".+,(dc=[^,]+,dc=[^,]+)$"
1098>      by dn.onelevel,expand="ou=Admin,$1" write
1099
1100where the regex in the {{<what>}} clause is more compact, and the one in the {{<by>}}
1101clause is replaced by a much more efficient scoping style of onelevel with substring expansion.
1102
1103
1104H3: Granting and Denying access based on security strength factors (ssf)
1105
1106You can restrict access based on the security strength factor (SSF)
1107
1108>    access to dn="cn=example,cn=edu"
1109>          by * ssf=256 read
1110
11110 (zero) implies no protection,
11121 implies integrity protection only,
111356 DES or other weak ciphers,
1114112 triple DES and other strong ciphers,
1115128 RC4, Blowfish and other modern strong ciphers.
1116
1117Other possibilities:
1118
1119>    transport_ssf=<n>
1120>    tls_ssf=<n>
1121>    sasl_ssf=<n>
1122
1123256 is recommended.
1124
1125See {{slapd.conf}}(5) for information on {{ssf}}.
1126
1127
1128H3: When things aren't working as expected
1129
1130Consider this example:
1131
1132>    access to *
1133>      by anonymous auth
1134>
1135>    access to *
1136>      by self write
1137>
1138>    access to *
1139>      by users read
1140
1141You may think this will allow any user to login, to read everything and change
1142his own data if he is logged in. But in this example only the login works and
1143an ldapsearch returns no data. The Problem is that SLAPD goes through its access
1144config line by line and stops as soon as it finds a match in the part of the
1145access rule.(here: {{to *}})
1146
1147To get what we wanted the file has to read:
1148
1149>    access to *
1150>      by anonymous auth
1151>      by self write
1152>      by users read
1153
1154The general rule is: "special access rules first, generic access rules last"
1155
1156See also {{slapd.access}}(8), loglevel 128 and {{slapacl}}(8) for debugging
1157information.
1158
1159
1160H2: Sets - Granting rights based on relationships
1161
1162Sets are best illustrated via examples. The following sections will present
1163a few set ACL examples in order to facilitate their understanding.
1164
1165(Sets in Access Controls FAQ Entry: {{URL:http://www.openldap.org/faq/data/cache/1133.html}})
1166
1167Note: Sets are considered experimental.
1168
1169
1170H3: Groups of Groups
1171
1172The OpenLDAP ACL for groups doesn't expand groups within groups, which are
1173groups that have another group as a member. For example:
1174
1175> dn: cn=sudoadm,ou=group,dc=example,dc=com
1176> cn: sudoadm
1177> objectClass: groupOfNames
1178> member: uid=john,ou=people,dc=example,dc=com
1179> member: cn=accountadm,ou=group,dc=example,dc=com
1180>
1181> dn: cn=accountadm,ou=group,dc=example,dc=com
1182> cn: accountadm
1183> objectClass: groupOfNames
1184> member: uid=mary,ou=people,dc=example,dc=com
1185
1186If we use standard group ACLs with the above entries and allow members of the
1187{{F:sudoadm}} group to write somewhere, {{F:mary}} won't be included:
1188
1189> access to dn.subtree="ou=sudoers,dc=example,dc=com"
1190>         by group.exact="cn=sudoadm,ou=group,dc=example,dc=com" write
1191>         by * read
1192
1193With sets we can make the ACL be recursive and consider group within groups. So
1194for each member that is a group, it is further expanded:
1195
1196> access to dn.subtree="ou=sudoers,dc=example,dc=com"
1197>       by set="[cn=sudoadm,ou=group,dc=example,dc=com]/member* & user" write
1198>       by * read
1199
1200This set ACL means: take the {{F:cn=sudoadm}} DN, check its {{F:member}}
1201attribute(s) (where the "{{F:*}}" means recursively) and intersect the result
1202with the authenticated user's DN. If the result is non-empty, the ACL is
1203considered a match and write access is granted.
1204
1205The following drawing explains how this set is built:
1206!import "set-recursivegroup.png"; align="center"; title="Building a recursive group"
1207FT[align="Center"] Figure X.Y: Populating a recursive group set
1208
1209First we get the {{F:uid=john}} DN. This entry doesn't have a {{F:member}}
1210attribute, so the expansion stops here.  Now we get to {{F:cn=accountadm}}.
1211This one does have a {{F:member}} attribute, which is {{F:uid=mary}}. The
1212{{F:uid=mary}} entry, however, doesn't have member, so we stop here again. The
1213end comparison is:
1214
1215> {"uid=john,ou=people,dc=example,dc=com","uid=mary,ou=people,dc=example,dc=com"} & user
1216
1217If the authenticated user's DN is any one of those two, write access is
1218granted. So this set will include {{F:mary}} in the {{F:sudoadm}} group and she
1219will be allowed the write access.
1220
1221H3: Group ACLs without DN syntax
1222
1223The traditional group ACLs, and even the previous example about recursive groups, require
1224that the members are specified as DNs instead of just usernames.
1225
1226With sets, however, it's also possible to use simple names in group ACLs, as this example will
1227show.
1228
1229Let's say we want to allow members of the {{F:sudoadm}} group to write to the
1230{{F:ou=suders}} branch of our tree. But our group definition now is using {{F:memberUid}} for
1231the group members:
1232
1233> dn: cn=sudoadm,ou=group,dc=example,dc=com
1234> cn: sudoadm
1235> objectClass: posixGroup
1236> gidNumber: 1000
1237> memberUid: john
1238
1239With this type of group, we can't use group ACLs. But with a set ACL we can
1240grant the desired access:
1241
1242> access to dn.subtree="ou=sudoers,dc=example,dc=com"
1243>       by set="[cn=sudoadm,ou=group,dc=example,dc=com]/memberUid & user/uid" write
1244>       by * read
1245
1246We use a simple intersection where we compare the {{F:uid}} attribute
1247of the connecting (and authenticated) user with the {{F:memberUid}} attributes
1248of the group. If they match, the intersection is non-empty and the ACL will
1249grant write access.
1250
1251This drawing illustrates this set when the connecting user is authenticated as
1252{{F:uid=john,ou=people,dc=example,dc=com}}:
1253!import "set-memberUid.png"; align="center"; title="Sets with memberUid"
1254FT[align="Center"] Figure X.Y: Sets with {{F:memberUid}}
1255
1256In this case, it's a match. If it were {{F:mary}} authenticating, however, she
1257would be denied write access to {{F:ou=sudoers}} because her {{F:uid}}
1258attribute is not listed in the group's {{F:memberUid}}.
1259
1260H3: Following references
1261
1262We will now show a quite powerful example of what can be done with sets. This
1263example tends to make OpenLDAP administrators smile after they have understood
1264it and its implications.
1265
1266Let's start with an user entry:
1267
1268> dn: uid=john,ou=people,dc=example,dc=com
1269> uid: john
1270> objectClass: inetOrgPerson
1271> givenName: John
1272> sn: Smith
1273> cn: john
1274> manager: uid=mary,ou=people,dc=example,dc=com
1275
1276Writing an ACL to allow the manager to update some attributes is quite simple
1277using sets:
1278
1279> access to dn.exact="uid=john,ou=people,dc=example,dc=com"
1280>    attrs=carLicense,homePhone,mobile,pager,telephoneNumber
1281>    by self write
1282>    by set="this/manager & user" write
1283>    by * read
1284
1285In that set, {{F:this}} expands to the entry being accessed, so that
1286{{F:this/manager}} expands to {{F:uid=mary,ou=people,dc=example,dc=com}} when
1287john's entry is accessed.  If the manager herself is accessing John's entry,
1288the ACL will match and write access to those attributes will be granted.
1289
1290So far, this same behavior can be obtained with the {{F:dnattr}} keyword. With
1291sets, however, we can further enhance this ACL. Let's say we want to allow the
1292secretary of the manager to also update these attributes. This is how we do it:
1293
1294> access to dn.exact="uid=john,ou=people,dc=example,dc=com"
1295>    attrs=carLicense,homePhone,mobile,pager,telephoneNumber
1296>    by self write
1297>    by set="this/manager & user" write
1298>    by set="this/manager/secretary & user" write
1299>    by * read
1300
1301Now we need a picture to help explain what is happening here (entries shortened
1302for clarity):
1303
1304!import "set-following-references.png"; align="center"; title="Sets jumping through entries"
1305FT[align="Center"] Figure X.Y: Sets jumping through entries
1306
1307In this example, Jane is the secretary of Mary, which is the manager of John.
1308This whole relationship is defined with the {{F:manager}} and {{F:secretary}}
1309attributes, which are both of the distinguishedName syntax (i.e., full DNs).
1310So, when the {{F:uid=john}} entry is being accessed, the
1311{{F:this/manager/secretary}} set becomes
1312{{F:{"uid=jane,ou=people,dc=example,dc=com"}}} (follow the references in the
1313picture):
1314
1315> this = [uid=john,ou=people,dc=example,dc=com]
1316> this/manager = \
1317>   [uid=john,ou=people,dc=example,dc=com]/manager = uid=mary,ou=people,dc=example,dc=com
1318> this/manager/secretary = \
1319>   [uid=mary,ou=people,dc=example,dc=com]/secretary = uid=jane,ou=people,dc=example,dc=com
1320
1321The end result is that when Jane accesses John's entry, she will be granted
1322write access to the specified attributes. Better yet, this will happen to any
1323entry she accesses which has Mary as the manager.
1324
1325This is all cool and nice, but perhaps gives to much power to secretaries. Maybe we need to further
1326restrict it. For example, let's only allow executive secretaries to have this power:
1327
1328> access to dn.exact="uid=john,ou=people,dc=example,dc=com"
1329>   attrs=carLicense,homePhone,mobile,pager,telephoneNumber
1330>   by self write
1331>   by set="this/manager & user" write
1332>   by set="this/manager/secretary &
1333>           [cn=executive,ou=group,dc=example,dc=com]/member* &
1334>           user" write
1335>   by * read
1336
1337It's almost the same ACL as before, but we now also require that the connecting user be a member
1338of the (possibly nested) {{F:cn=executive}} group.
1339
1340
1341