<?xml version="1.0" encoding="UTF-8"?>
|
<!--
|
! CCPL HEADER START
|
!
|
! This work is licensed under the Creative Commons
|
! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
|
! To view a copy of this license, visit
|
! http://creativecommons.org/licenses/by-nc-nd/3.0/
|
! or send a letter to Creative Commons, 444 Castro Street,
|
! Suite 900, Mountain View, California, 94041, USA.
|
!
|
! You can also obtain a copy of the license at
|
! trunk/opendj3/legal-notices/CC-BY-NC-ND.txt.
|
! See the License for the specific language governing permissions
|
! and limitations under the License.
|
!
|
! If applicable, add the following below this CCPL HEADER, with the fields
|
! enclosed by brackets "[]" replaced with your own identifying information:
|
! Portions Copyright [yyyy] [name of copyright owner]
|
!
|
! CCPL HEADER END
|
!
|
! Copyright 2011-2013 ForgeRock AS
|
!
|
-->
|
<chapter xml:id='chap-groups'
|
xmlns='http://docbook.org/ns/docbook' version='5.0' xml:lang='en'
|
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
|
xsi:schemaLocation='http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd'
|
xmlns:xlink='http://www.w3.org/1999/xlink'
|
xmlns:xinclude='http://www.w3.org/2001/XInclude'>
|
<title>Working With Groups of Entries</title>
|
|
<para>OpenDJ supports several methods of grouping entries in the directory.
|
Static groups list their members, whereas dynamic groups look up their
|
membership based on an LDAP filter. OpenDJ also supports virtual static
|
groups, which uses a dynamic group style definition, but allows applications
|
to list group members as if the group were static.</para>
|
|
<para>When listing entries in static groups, you must also have a mechanism
|
for removing entries from the list when they are deleted or modified in ways
|
that end their membership. OpenDJ makes that possible with
|
<emphasis>referential integrity</emphasis> functionality.</para>
|
|
<para>This chapter demonstrates how to work with groups.</para>
|
|
<tip>
|
<para>The examples in this chapter assume that an
|
<literal>ou=Groups,dc=example,dc=com</literal> entry already exists. If you
|
imported data from <link xlink:href="http://opendj.forgerock.org/Example.ldif"
|
xlink:show="new">Example.ldif</link>, then you already have the entry. If you
|
generated data during setup and did not create an organizational unit for
|
groups yet, create the entry before you try the examples.</para>
|
|
<screen>$ ldapmodify
|
--defaultAdd
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
dn: ou=Groups,dc=example,dc=com
|
objectClass: organizationalunit
|
objectClass: top
|
ou: Groups
|
|
Processing ADD request for ou=Groups,dc=example,dc=com
|
ADD operation successful for DN ou=Groups,dc=example,dc=com</screen>
|
</tip>
|
|
<section xml:id="static-groups">
|
<title>Creating Static Groups</title>
|
<indexterm>
|
<primary>Groups</primary>
|
<secondary>Static</secondary>
|
</indexterm>
|
|
<para>A <firstterm>static group</firstterm> is expressed as an entry
|
that enumerates all the entries that belong to the group. Static group
|
entries grow as their membership increases.</para>
|
|
<para>Static group entries can take the standard object class
|
<literal>groupOfNames</literal> where each <literal>member</literal>
|
attribute value is a distinguished name of an entry, or
|
<literal>groupOfUniqueNames</literal> where each
|
<literal>uniqueMember</literal> attribute value has Name and Optional UID
|
syntax.<footnote><para>Name and Optional UID syntax values are a DN optionally
|
followed by <literal>#<replaceable>BitString</replaceable></literal>. The
|
<replaceable>BitString</replaceable>, such as <literal>'0101111101'B</literal>,
|
serves to distinguish the entry from another entry having the same DN, which
|
can occur when the original entry was deleted and a new entry created with the
|
same DN.</para></footnote> Like other LDAP attributes,
|
<literal>member</literal> and <literal>uniqueMember</literal> attributes take
|
sets of unique values.</para>
|
|
<para>Static group entries can also have the object class
|
<literal>groupOfEntries</literal>, which is like
|
<literal>groupOfNames</literal> except that it is designed to allow
|
groups not to have members.</para>
|
|
<para>When creating a group entry, use <literal>groupOfNames</literal> or
|
<literal>groupOfEntries</literal> where possible.</para>
|
|
<para>To create a static group, add a group entry such as the following
|
to the directory.</para>
|
|
<screen>$ cat static.ldif
|
dn: cn=My Static Group,ou=Groups,dc=example,dc=com
|
cn: My Static Group
|
objectClass: groupOfNames
|
objectClass: top
|
ou: Groups
|
member: uid=ahunter,ou=People,dc=example,dc=com
|
member: uid=bjensen,ou=People,dc=example,dc=com
|
member: uid=tmorris,ou=People,dc=example,dc=com
|
|
$ ldapmodify
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
--defaultAdd
|
--filename static.ldif
|
Processing ADD request for cn=My Static Group,ou=Groups,dc=example,dc=com
|
ADD operation successful for DN cn=My Static Group,ou=Groups,dc=example,dc=com</screen>
|
|
<para>To change group membership, modify the values of the membership
|
attribute.</para>
|
|
<screen>$ cat add2grp.ldif
|
dn: cn=My Static Group,ou=Groups,dc=example,dc=com
|
changetype: modify
|
add: member
|
member: uid=scarter,ou=People,dc=example,dc=com
|
|
$ ldapmodify
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
--filename add2grp.ldif
|
Processing MODIFY request for cn=My Static Group,ou=Groups,dc=example,dc=com
|
MODIFY operation successful for DN
|
cn=My Static Group,ou=Groups,dc=example,dc=com
|
$ ldapsearch
|
--port 1389
|
--baseDN dc=example,dc=com
|
"(cn=My Static Group)"
|
dn: cn=My Static Group,ou=Groups,dc=example,dc=com
|
ou: Groups
|
objectClass: groupOfNames
|
objectClass: top
|
member: uid=ahunter,ou=People,dc=example,dc=com
|
member: uid=bjensen,ou=People,dc=example,dc=com
|
member: uid=tmorris,ou=People,dc=example,dc=com
|
member: uid=scarter,ou=People,dc=example,dc=com
|
cn: My Static Group</screen>
|
|
<para>RFC 4519 says a <literal>groupOfNames</literal> entry must have
|
at least one member. Although OpenDJ allows you to create a
|
<literal>groupOfNames</literal> without members, strictly speaking that
|
behavior is not standard. Alternatively, you can use the
|
<literal>groupOfEntries</literal> object class as shown in the following
|
example.</para>
|
|
<screen>$ cat group-of-entries.ldif
|
dn: cn=Initially Empty Static Group,ou=Groups,dc=example,dc=com
|
cn: Initially Empty Static Group
|
objectClass: groupOfEntries
|
objectClass: top
|
ou: Groups
|
|
$ ldapmodify
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
--defaultAdd
|
--filename group-of-entries.ldif
|
Processing ADD request for
|
cn=Initially Empty Static Group,ou=Groups,dc=example,dc=com
|
ADD operation successful for DN
|
cn=Initially Empty Static Group,ou=Groups,dc=example,dc=com
|
$ cat add-members.ldif
|
# Now add some members to the group.
|
dn: cn=Initially Empty Static Group,ou=Groups,dc=example,dc=com
|
changetype: modify
|
add: member
|
member: uid=ahunter,ou=People,dc=example,dc=com
|
member: uid=bjensen,ou=People,dc=example,dc=com
|
member: uid=tmorris,ou=People,dc=example,dc=com
|
member: uid=scarter,ou=People,dc=example,dc=com
|
|
$ ldapmodify
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
--filename add-members.ldif
|
Processing MODIFY request for
|
cn=Initially Empty Static Group,ou=Groups,dc=example,dc=com
|
MODIFY operation successful for DN
|
cn=Initially Empty Static Group,ou=Groups,dc=example,dc=com</screen>
|
</section>
|
|
<section xml:id="dynamic-groups">
|
<title>Creating Dynamic Groups</title>
|
<indexterm>
|
<primary>Groups</primary>
|
<secondary>Dynamic</secondary>
|
</indexterm>
|
|
<para>A <firstterm>dynamic group</firstterm> specifies members using
|
LDAP URLs. Dynamic groups entries can stay small even as their
|
membership increases.</para>
|
|
<para>Dynamic group entries take the <literal>groupOfURLs</literal>
|
object class, with one or more <literal>memberURL</literal> values
|
specifying LDAP URLs to identify group members.</para>
|
|
<para>To create a dynamic group, add a group entry such as the following to
|
the directory.</para>
|
|
<para>The following example builds a dynamic group of entries effectively
|
matching the filter <literal>"(l=Cupertino)"</literal> (users whose location
|
is Cupertino). Change the filter if your data is different, and so no
|
entries have <literal>l: Cupertino</literal>.</para>
|
|
<screen>$ cat dynamic.ldif
|
dn: cn=My Dynamic Group,ou=Groups,dc=example,dc=com
|
cn: My Dynamic Group
|
objectClass: top
|
objectClass: groupOfURLs
|
ou: Groups
|
memberURL: ldap:///ou=People,dc=example,dc=com??sub?l=Cupertino
|
|
$ ldapmodify
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
--defaultAdd
|
--filename dynamic.ldif
|
Processing ADD request for cn=My Dynamic Group,ou=Groups,dc=example,dc=com
|
ADD operation successful for DN cn=My Dynamic Group,ou=Groups,dc=example,dc=com</screen>
|
|
<para>Group membership changes dynamically as entries change to match the
|
<literal>memberURL</literal> values.</para>
|
|
<screen>$ ldapsearch
|
--port 1389
|
--baseDN dc=example,dc=com
|
"(&(uid=*jensen)(isMemberOf=cn=My Dynamic Group,ou=Groups,dc=example,dc=com))"
|
mail
|
dn: uid=bjensen,ou=People,dc=example,dc=com
|
mail: bjensen@example.com
|
|
dn: uid=rjensen,ou=People,dc=example,dc=com
|
mail: rjensen@example.com
|
|
$ ldapmodify
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
dn: uid=ajensen,ou=People,dc=example,dc=com
|
changetype: modify
|
replace: l
|
l: Cupertino
|
|
Processing MODIFY request for uid=ajensen,ou=People,dc=example,dc=com
|
MODIFY operation successful for DN uid=ajensen,ou=People,dc=example,dc=com
|
^D
|
$ ldapsearch
|
--port 1389
|
--baseDN dc=example,dc=com
|
"(&(uid=*jensen)(isMemberOf=cn=My Dynamic Group,ou=Groups,dc=example,dc=com))"
|
mail
|
dn: uid=ajensen,ou=People,dc=example,dc=com
|
mail: ajensen@example.com
|
|
dn: uid=bjensen,ou=People,dc=example,dc=com
|
mail: bjensen@example.com
|
|
dn: uid=rjensen,ou=People,dc=example,dc=com
|
mail: rjensen@example.com</screen>
|
</section>
|
|
<section xml:id="virtual-static-groups">
|
<title>Creating Virtual Static Groups</title>
|
<indexterm>
|
<primary>Groups</primary>
|
<secondary>Virtual static</secondary>
|
</indexterm>
|
|
<para>OpenDJ lets you create <firstterm>virtual static groups</firstterm>,
|
which let applications see dynamic groups as what appear to be static
|
groups.</para>
|
|
<para>The virtual static group takes auxiliary object class
|
<literal>ds-virtual-static-group</literal>. Virtual static groups also take
|
either the object class <literal>groupOfNames</literal>, or
|
<literal>groupOfUniqueNames</literal>, but instead of having
|
<literal>member</literal> or <literal>uniqueMember</literal> attributes,
|
have <literal>ds-target-group-dn</literal> attributes pointing to other
|
groups.</para>
|
|
<para>Generating the list of members can be resource intensive for large
|
groups, so by default you cannot retrieve the list of members. You can
|
change this with the <command>dsconfig</command> command by setting the
|
<literal>Virtual Static member</literal> or
|
<literal>Virtual Static uniqueMember</literal> property.</para>
|
|
<screen>$ dsconfig
|
set-virtual-attribute-prop
|
--port 4444
|
--hostname opendj.example.com
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
--name "Virtual Static member"
|
--set allow-retrieving-membership:true
|
--trustAll
|
--no-prompt</screen>
|
|
<para>The following example creates a virtual static group, and reads the
|
group entry with all members.</para>
|
|
<screen>$ cat virtual.ldif
|
dn: cn=Virtual Static,ou=Groups,dc=example,dc=com
|
cn: Virtual Static
|
objectclass: top
|
objectclass: groupOfNames
|
objectclass: ds-virtual-static-group
|
ds-target-group-dn: cn=My Dynamic Group,ou=Groups,dc=example,dc=com
|
|
$ ldapmodify
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
--defaultAdd
|
--filename virtual.ldif
|
Processing ADD request for cn=Virtual Static,ou=Groups,dc=example,dc=com
|
ADD operation successful for DN cn=Virtual Static,ou=Groups,dc=example,dc=com
|
$ ldapsearch --port 1389 --baseDN dc=example,dc=com "(cn=Virtual Static)"
|
dn: cn=Virtual Static,ou=Groups,dc=example,dc=com
|
objectClass: groupOfNames
|
objectClass: ds-virtual-static-group
|
objectClass: top
|
member: uid=jwalker,ou=People,dc=example,dc=com
|
member: uid=jmuffly,ou=People,dc=example,dc=com
|
member: uid=tlabonte,ou=People,dc=example,dc=com
|
member: uid=dakers,ou=People,dc=example,dc=com
|
member: uid=jreuter,ou=People,dc=example,dc=com
|
member: uid=rfisher,ou=People,dc=example,dc=com
|
member: uid=pshelton,ou=People,dc=example,dc=com
|
member: uid=rjensen,ou=People,dc=example,dc=com
|
member: uid=jcampaig,ou=People,dc=example,dc=com
|
member: uid=mjablons,ou=People,dc=example,dc=com
|
member: uid=mlangdon,ou=People,dc=example,dc=com
|
member: uid=aknutson,ou=People,dc=example,dc=com
|
member: uid=bplante,ou=People,dc=example,dc=com
|
member: uid=awalker,ou=People,dc=example,dc=com
|
member: uid=smason,ou=People,dc=example,dc=com
|
member: uid=ewalker,ou=People,dc=example,dc=com
|
member: uid=dthorud,ou=People,dc=example,dc=com
|
member: uid=btalbot,ou=People,dc=example,dc=com
|
member: uid=tcruse,ou=People,dc=example,dc=com
|
member: uid=kcarter,ou=People,dc=example,dc=com
|
member: uid=aworrell,ou=People,dc=example,dc=com
|
member: uid=bjensen,ou=People,dc=example,dc=com
|
member: uid=ajensen,ou=People,dc=example,dc=com
|
member: uid=cwallace,ou=People,dc=example,dc=com
|
member: uid=mwhite,ou=People,dc=example,dc=com
|
member: uid=kschmith,ou=People,dc=example,dc=com
|
member: uid=mtalbot,ou=People,dc=example,dc=com
|
member: uid=tschmith,ou=People,dc=example,dc=com
|
member: uid=gfarmer,ou=People,dc=example,dc=com
|
member: uid=speterso,ou=People,dc=example,dc=com
|
member: uid=prose,ou=People,dc=example,dc=com
|
member: uid=jbourke,ou=People,dc=example,dc=com
|
member: uid=mtyler,ou=People,dc=example,dc=com
|
member: uid=abergin,ou=People,dc=example,dc=com
|
member: uid=mschneid,ou=People,dc=example,dc=com
|
cn: Virtual Static
|
ds-target-group-dn: cn=My Dynamic Group,ou=Groups,dc=example,dc=com</screen>
|
</section>
|
|
<section xml:id="group-membership">
|
<title>Looking Up Group Membership</title>
|
<indexterm>
|
<primary>Groups</primary>
|
<secondary>Membership</secondary>
|
</indexterm>
|
|
<para>OpenDJ lets you look up which groups a user belongs to by using the
|
<literal>isMemberOf</literal> attribute.</para>
|
|
<screen>$ ldapsearch
|
--port 1389
|
--baseDN dc=example,dc=com
|
uid=bjensen
|
isMemberOf
|
dn: uid=bjensen,ou=People,dc=example,dc=com
|
isMemberOf: cn=My Static Group,ou=Groups,dc=example,dc=com
|
isMemberOf: cn=Virtual Static,ou=Groups,dc=example,dc=com
|
isMemberOf: cn=My Dynamic Group,ou=Groups,dc=example,dc=com</screen>
|
|
<para>You must request <literal>isMemberOf</literal> explicitly.</para>
|
</section>
|
|
<section xml:id="referential-integrity">
|
<title>Configuring Referential Integrity</title>
|
<indexterm>
|
<primary>Groups</primary>
|
<secondary>Referential integrity</secondary>
|
</indexterm>
|
|
<para>When you delete or rename an entry that belongs to static groups, that
|
entry's DN must be removed or changed in the list of each group to which it
|
belongs. You can configure OpenDJ to resolve membership on your behalf after
|
the change operation succeeds by enabling referential integrity.</para>
|
|
<para>Referential integrity functionality is implemented as a plugin. The
|
referential integrity plugin is disabled by default. To enable the plugin,
|
use the <command>dsconfig</command> command.</para>
|
|
<screen>$ dsconfig
|
set-plugin-prop
|
--port 4444
|
--hostname opendj.example.com
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
--plugin-name "Referential Integrity"
|
--set enabled:true
|
--trustAll --no-prompt</screen>
|
|
<para>With the plugin enabled, you can see OpenDJ referential integrity
|
resolving group membership automatically.</para>
|
|
<screen>$ ldapsearch --port 1389 --baseDN dc=example,dc=com "(cn=My Static Group)"
|
dn: cn=My Static Group,ou=Groups,dc=example,dc=com
|
ou: Groups
|
objectClass: groupOfNames
|
objectClass: top
|
member: uid=ahunter,ou=People,dc=example,dc=com
|
member: uid=bjensen,ou=People,dc=example,dc=com
|
member: uid=tmorris,ou=People,dc=example,dc=com
|
member: uid=scarter,ou=People,dc=example,dc=com
|
cn: My Static Group
|
|
$ ldapdelete
|
--port 1389
|
--bindDN "cn=Directory Manager"
|
--bindPassword password
|
uid=scarter,ou=People,dc=example,dc=com
|
Processing DELETE request for uid=scarter,ou=People,dc=example,dc=com
|
DELETE operation successful for DN uid=scarter,ou=People,dc=example,dc=com
|
$ ldapsearch --port 1389 --baseDN dc=example,dc=com "(cn=My Static Group)"
|
dn: cn=My Static Group,ou=Groups,dc=example,dc=com
|
ou: Groups
|
objectClass: groupOfNames
|
objectClass: top
|
cn: My Static Group
|
member: uid=ahunter,ou=People,dc=example,dc=com
|
member: uid=bjensen,ou=People,dc=example,dc=com
|
member: uid=tmorris,ou=People,dc=example,dc=com</screen>
|
|
<para>By default the referential integrity plugin is configured to manage
|
<literal>member</literal> and <literal>uniqueMember</literal> attributes.
|
These attributes take values that are DNs, and are indexed for equality by
|
default. Before you add an additional attribute to manage, make sure that
|
it has DN syntax and that it is indexed for equality. OpenDJ requires that
|
the attribute be indexed because an unindexed search for integrity would
|
potentially consume too many of the server's resources. Attribute syntax is
|
explained in the chapter on <link xlink:href="admin-guide#chap-schema"
|
xlink:show="new" xlink:role="http://docbook.org/xlink/role/olink"><citetitle
|
>Managing Schema</citetitle></link>. For instructions on indexing attributes,
|
see the section on <link xlink:href="admin-guide#configure-indexes"
|
xlink:show="new" xlink:role="http://docbook.org/xlink/role/olink"><citetitle
|
>Configuring & Rebuilding Indexes</citetitle></link>.</para>
|
|
<para>You can also configure the referential integrity plugin to check that
|
new entries added to groups actually exist in the directory by setting the
|
<literal>check-references</literal> property to <literal>true</literal>. You
|
can specify additional criteria once you have activated the check. To ensure
|
that entries added must match a filter, set the
|
<literal>check-references-filter-criteria</literal> to identify the attribute
|
and the filter. For example, you can specify that group members must be person
|
entries by setting <literal>check-references-filter-criteria</literal> to
|
<literal>member:(objectclass=person)</literal>. To ensure that entries must be
|
located in the same naming context, set
|
<literal>check-references-scope-criteria</literal> to
|
<literal>naming-context</literal>.</para>
|
</section>
|
</chapter>
|