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