From 53fa7f906e85d25624a107a7414856b9aaed3b11 Mon Sep 17 00:00:00 2001
From: Jesse Coretta <74126726+JesseCoretta@users.noreply.github.com>
Date: Wed, 18 Sep 2024 07:54:46 +0000
Subject: [PATCH] Addresses #397, #398, #399, #404 (#405)
---
opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-privileges-acis.xml | 32 ++
opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-connection-handlers.xml | 6
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java | 2
opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-schema.xml | 514 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 545 insertions(+), 9 deletions(-)
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java
index daa6063..1cb6595 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRule.java
@@ -687,7 +687,7 @@
final String firstClass = iterator.next();
if (iterator.hasNext()) {
- buffer.append(" AUX (");
+ buffer.append(" AUX ( ");
buffer.append(firstClass);
while (iterator.hasNext()) {
diff --git a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-connection-handlers.xml b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-connection-handlers.xml
index 833cd9f..72f9a03 100644
--- a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-connection-handlers.xml
+++ b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-connection-handlers.xml
@@ -457,7 +457,7 @@
The password for the key store and the private key is stored in clear text
in the file <filename>/path/to/opendj/config/keystore.pin</filename>.</para>
- <para>If you want to secure communications, but did not chose to configure
+ <para>If you want to secure communications, but chose not to configure
LDAP Secure Access at setup time, this procedure can help. The following
steps explain how to create and install a key pair with a self-signed
certificate in preparation to configure LDAPS or HTTPS. First you create a
@@ -699,8 +699,8 @@
<para>Using the OpenDJ directory server global configuration properties, you
can add global restrictions on how clients access the server. These settings
- are per server, and so much be set independently on each server in replication
- topology.</para>
+ are server-specific, and must be set independently on each server participating
+ within the replication topology.</para>
<para>These global settings are fairly coarse-grained. For a full discussion
of the rich set of administrative privileges and fine-grained access control
diff --git a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-privileges-acis.xml b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-privileges-acis.xml
index 168b7c5..d483961 100644
--- a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-privileges-acis.xml
+++ b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-privileges-acis.xml
@@ -264,6 +264,22 @@
</listitem>
</varlistentry>
</variablelist>
+ <note>
+ <para>Different LDAP server implementations that support Netscape's ACI syntax
+ may support different multi-valued quotation styles or policies. Specifically,
+ this can relate to <replaceable>attr-list</replaceable> and <replaceable>OID</replaceable>
+ values.</para>
+ <para>OpenDJ ONLY offers support for the so-called "All-Encompassing" quotation
+ style, as is demonstrated throughout this guide. For instance:</para>
+ <literal>(targetattr = "<replaceable>attr1 || attr2 || attr3</replaceable>")</literal>
+ <para>Other implementations may also support the so-called "Individual" quotation
+ style, which is expressed as:</para>
+ <literal>(targetattr = <replaceable>"attr1" || "attr2" || "attr3"</replaceable>)</literal>
+ <para>Users migrating to OpenDJ from an implementation that not only supports the
+ "Individual" quotation style, but is actively using it, will need to take care to
+ sanitize any inbound ACIs bearing this style of quotation, else errors will occur
+ during integration.</para>
+ </note>
</section>
<section xml:id="aci-permissions">
@@ -1007,11 +1023,17 @@
<para>Collective attributes provide a standard mechanism for defining
attributes that appear on all the entries in a particular subtree. OpenDJ
extends collective attributes to give you fine-grained control over the
- which entries in the subtree are targetted. Also, OpenDJ lets you use
- virtual attributes, such as <literal>isMemberOf</literal> to construct the
- filter for targetting entries to which the collective attributes apply. This
- allows you, for example, to define administrative privileges that apply to
- all users who belong to an administrator group.</para>
+ which entries in the subtree are targeted.</para>
+
+ <para>Also, by also extending the RFC 3672 <literal>SpecificationFilter</literal>
+ component, users may leverage virtual attributes, such as <literal>isMemberOf</literal>,
+ to construct a search filter for targeting entries to which the collective
+ attributes apply. This allows you, for example, to define administrative
+ privileges that apply to all users who belong to an administrator group.</para>
+
+ <para>In addition to this feature, the traditional <literal>Refinement</literal>
+ <literal>ASN.1 CHOICE</literal> component -- also defined within RFC 3672 -- is
+ supported for use as a <literal>SpecificationFilter</literal> statement as well.</para>
<step>
<para>Create an LDAP subentry that specifies the collective attributes.</para>
diff --git a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-schema.xml b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-schema.xml
index b77e159..e2417d0 100644
--- a/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-schema.xml
+++ b/opendj-doc-generated-ref/src/main/docbkx/admin-guide/chap-schema.xml
@@ -629,4 +629,518 @@
</varlistentry>
</variablelist>
</section>
+ <section xml:id="nf-dsr-schema">
+ <title>Working With DIT Structure Rules & Name Forms</title>
+ <para>This section contains useful information regarding name forms and
+ DIT structure rules.</para>
+ <note>At this time, the OpenDJ Control Panel does not support the management
+ of name forms and DIT structure rules. These schema definition types can
+ only be implemented and managed by way of direct schema file edits (which will
+ necessitate a restart of OpenDJ), <emphasis>or</emphasis> through a use of
+ <command>ldapmodify</command> against the server's <literal>cn=schema</literal>
+ context.</note>
+ <section xml:id="nf-schema">
+ <title>Name Forms</title>
+ <para>From clause 13.1.8 of <link xlink:href="https://www.itu.int/rec/T-REC-X.501" xlink:show="new">
+ <citetitle>ITU-T Rec. X.501</citetitle></link> and <link xlink:href="http://tools.ietf.org/html/rfc4512#section-4.1.7.2" xlink:show="new">
+ <citetitle>Section 4.1.7.2 of RFC 4512</citetitle></link></para>
+ <variablelist>
+ <varlistentry>
+ <listitem>
+ <emphasis>name form: A name form specifies a permissible RDN for entries
+ of a particular structural object class. A name form identifies a named object
+ class and one or more attribute types to be used for naming (i.e., for the
+ RDN). Name forms are primitive pieces of specification used in the definition
+ of DIT structure rules.</emphasis>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>In simplest terms, a name form is a particular schema definition which
+ requires specific RDN syntaxes for use upon entries bearing a specific
+ STRUCTURAL class.</para>
+ <para>To offer an example of this, consider the following UDDIv3 name form, per
+ the <filename>03-uddiv3.ldif</filename> file included with OpenDJ:</para>
+ <screen>
+ nameForms: ( 1.3.6.1.1.10.15.1
+ NAME 'uddiBusinessEntityNameForm'
+ OC uddiBusinessEntity
+ MUST ( uddiBusinessKey )
+ X-ORIGIN 'RFC 4403' )</screen>
+ <para>This name form states that any entry bearing the STRUCTURAL class
+ <literal>uddiBusinessEntity</literal> MUST ONLY be designated using the
+ <literal>uddiBusinessKey</literal> as the principal RDN attribute type, for
+ example, "<literal>uddiBusinessKey=ABC123</literal>".</para>
+ <para>Alternatively, when devising custom name forms, it is possible to enforce
+ the use of specific attribute types within multi-valued RDNs. Consider the following
+ hypothetical name form:</para>
+ <screen>
+ nameForms: ( 1.3.6.1.4.1.56521.999.98.15
+ NAME 'cnOrgForm'
+ OC groupOfUniqueNames
+ MUST ( cn $ o ) )</screen>
+ <para>This name form states that any entry bearing the STRUCTURAL object class
+ <literal>groupOfUniqueNames</literal> MUST be designated using attribute types
+ <literal>cn</literal> <emphasis>and</emphasis> <literal>o</literal> for a
+ qualifying entry bearing a multi-valued RDN, such as
+ "<literal>cn=Auditors+o=Acme Audit Co</literal>".</para>
+ <para>Name forms also allow use of MAY clauses. Consider the following
+ hypothetical name form, similar to the above:</para>
+ <screen>
+ nameForms: ( 1.3.6.1.4.1.56521.999.98.16
+ NAME 'cnOrgAltForm'
+ OC groupOfUniqueNames
+ MUST cn
+ MAY o )</screen>
+ <para>This rule enforces use of the <literal>cn</literal> RDN attribute type the
+ same as before, but while it no longer requires use of <literal>o</literal>, it
+ will not reject it when present. As such, either of the following RDNs are acceptable:</para>
+ <itemizedlist>
+ <listitem><literal>cn=Corporate Auditors</literal></listitem>
+ <listitem><literal>cn=Third Party Auditors+o=Acme Audit Co</literal></listitem>
+ </itemizedlist>
+ <para>But, regardless of the permutations, a name form does little good in practice
+ -- unless it is referenced by a DIT structure rule.</para>
+ </section>
+ <section xml:id="dsr-schema">
+ <title>DIT Structure Rules</title>
+ <para>From clause 13.1.6 of <link xlink:href="https://www.itu.int/rec/T-REC-X.501" xlink:show="new">
+ <citetitle>ITU-T Rec. X.501</citetitle></link> and <link xlink:href="http://tools.ietf.org/html/rfc4512#section-4.1.7.1" xlink:show="new">
+ <citetitle>Section 4.1.7.1 of RFC 4512</citetitle></link></para>
+ <variablelist>
+ <varlistentry>
+ <listitem><emphasis>DIT structure rule: A rule governing the structure of the DIT
+ by specifying a permitted superior to subordinate entry relationship. A structure
+ rule relates a name form, and therefore a structural object class, to superior
+ structure rules. This permits entries of the structural object class identified
+ by the name form to exist in the DIT as subordinates to entries governed by the
+ indicated superior structure rules.</emphasis></listitem>
+ </varlistentry>
+ </variablelist>
+ <para>In short, a DIT structure rule enforces the terms of its prescribed name form.
+ To offer a simple analogy, if a name form presents a law, the DIT structure rule is
+ the public official upholding that law.</para>
+ <para>Consider this structure rule, per the included <filename>03-uddiv3.ldif</filename>
+ file:</para>
+ <screen>
+ dITStructureRules: ( 1
+ NAME 'uddiBusinessEntityStructureRule'
+ FORM uddiBusinessEntityNameForm
+ X-ORIGIN 'RFC 4403' )</screen>
+ <para>This rule employs the <literal>uddiBusinessEntityNameForm</literal> definition,
+ and constrains entries bearing the STRUCTURAL object class of the name form -- also
+ known as the <literal>namedObjectClass</literal> -- to the RDN attribute type (in this
+ case, <literal>uddiBusinessKey</literal>).</para>
+ <para>When a DIT structure rule is introduced to the directory schema, it will not
+ be evaluated until an entry is added to the DIT it enforces.</para>
+ <para>DIT structure rules shall not influence preexisting entries, even if based
+ upon now-illegal STRUCTURAL class and RDN combinations.</para>
+ <para>Once structure rules have been established, when a new entry is added to, or
+ renamed within the DIT in violation of a structure rule, OpenDJ will return "Object
+ class violation (65)" along with additional contextual information for debugging
+ purposes.</para>
+ <note><para>As of version 4.8.0, OpenDJ is currently using the result code of "Object
+ class violation (65)" for certain name form related errors, where it should be using
+ "Naming violation (64)".</para>
+ <para>This issue will be resolved in a future release of the package to avoid introducing
+ breaking changes. Users are advised to update any external scripts or applications which
+ may match the <emphasis>incorrect result code</emphasis>, and take steps to allow recognition
+ of the <emphasis>correct result code</emphasis> in parallel for maximum compatibility.</para></note>
+ <para>But when a new entry is successfully added to or renamed within the DIT, a new
+ operational attribute type appears on the entry: <literal>governingStructureRule</literal>.</para>
+ <para>From clause 13.1.7 of <link xlink:href="https://www.itu.int/rec/T-REC-X.501" xlink:show="new">
+ <citetitle>ITU-T Rec. X.501:</citetitle></link></para>
+ <variablelist>
+ <varlistentry>
+ <listitem>
+ <emphasis>Governing structure rule (of an entry): With respect to a particular
+ entry, the single DIT structure rule that applies to the entry. This rule is indicated
+ by the governingStructureRule operational attribute.</emphasis>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>See also <link xlink:href="http://tools.ietf.org/html/rfc4512#section-3.4.6" xlink:show="new">
+ <citetitle>Section 3.4.6 of RFC 4512</citetitle></link>.</para>
+ <para>In simplest terms, the <literal>governingStructureRule</literal> contains
+ the integer identifier of the DIT structure rule which governs the entry. In the
+ case of the above DIT structure rule, it would appear in LDAP search results as
+ follows:</para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>governingStructureRule: 1</literal></term>
+ </varlistentry>
+ </variablelist>
+ <para>Instances of this attribute type may be used for diagnostic reasons, or
+ by client applications designed to determine the appropriate RDN syntax to
+ be applied for a new entry, or for an entry being renamed and/or moved, in
+ advance of the request.</para>
+ <para>DIT structure rules can be configured in such a way that a particular rule
+ extends from, or is subordinate to, another DIT structure rule using the SUP clause.</para>
+ <tip>A superior DIT structure rule is often referred to as a superior structure
+ rule, per clause 13.1.9 of <link xlink:href="https://www.itu.int/rec/T-REC-X.501" xlink:show="new">
+ <citetitle>ITU-T Rec. X.501</citetitle></link>.</tip>
+ <para>The purpose of the SUP clause is to allow an entry with a particular RDN
+ syntax to reside beneath one of multiple possible choices. For example:</para>
+ <variablelist>
+ <varlistentry>
+ <screen>SUP ( 20 21 )</screen>
+ </varlistentry>
+ </variablelist>
+ <para>In this example, the integer identifiers 20 and 21 indicate that the bearer
+ of this clause will allow entries to reside as subordinates to <emphasis>either</emphasis>
+ of the entries governed by those rules.</para>
+ <para>Also note that rules can be <emphasis>recursive</emphasis> or "self-referencing".
+ This manifests as an instance where a DIT structure rule possesses a SUP clause member
+ that matches its own integer identifier. This is a particularly useful feature because
+ it allows nesting of compliant entries -- for example, those bearing the <literal>organizationalUnit</literal>
+ STRUCTURAL class -- to exist within superior entries of like-design.</para>
+ <para>For an example of recursive rules in action, see the <literal>ouStructure</literal>
+ rule (21) in the next section.</para>
+ </section>
+ <section xml:id="dsr-dit-design-schema">
+ <title>DIT Design Under Governance - A Practical Overview</title>
+ <para>This section will cover the highlights of creating initial DIT content while
+ under the control of easily-understood DIT structure rules enforcing the use of
+ common attribute types within entry RDNs.</para>
+ <para>The following basic assumptions apply:</para>
+ <itemizedlist>
+ <listitem><para>A new <literal>userRoot</literal> backend exists <emphasis>and</emphasis>
+ is identified by the <literal>base-dn</literal> of <literal>dc=example,dc=com</literal>,
+ containing no entries whatsoever, and ...</para></listitem>
+ <listitem><para>The eight (8) definitions described have already been saved
+ to <literal>/opt/opendj/config/schema/99-user.ldif</literal> or a similar
+ file, or otherwise added via <command>ldapmodify</command></para></listitem>
+ </itemizedlist>
+ <para>To begin, let's take a look at the following <literal>nameForms</literal>
+ definitions:</para>
+ <screen>
+ #
+ nameForms: ( 1.3.6.1.4.1.56521.999.2.7.1
+ NAME 'rootSuffixForm'
+ OC domain
+ MUST dc )
+ #
+ nameForms: ( 1.3.6.1.4.1.56521.999.2.7.2
+ NAME 'ouForm'
+ OC organizationalUnit
+ MUST ou )
+ #
+ nameForms: ( 1.3.6.1.4.1.56521.999.2.7.3
+ NAME 'accountForm'
+ OC inetOrgPerson
+ MUST uid )
+ #
+ nameForms: ( 1.3.6.1.4.1.56521.999.2.7.4
+ NAME 'groupForm'
+ OC groupOfNames
+ MUST cn )</screen>
+ <para>These name forms declare the following mandates:</para>
+ <itemizedlist>
+ <listitem>Entries bearing the <literal>domain</literal> STRUCTURAL class,
+ MUST utilize <literal>dc</literal> for their respective RDNs</listitem>
+ <listitem>Entries bearing the <literal>organizationalUnit</literal> STRUCTURAL
+ class, MUST utilize <literal>ou</literal> for their respective RDNs</listitem>
+ <listitem>Entries bearing the <literal>inetOrgPerson</literal> STRUCTURAL class,
+ MUST utilize <literal>uid</literal> for their respective RDNs</listitem>
+ <listitem>Entries bearing the <literal>groupOfNames</literal> STRUCTURAL class,
+ MUST utilize <literal>cn</literal> for their respective RDNs</listitem>
+ </itemizedlist>
+ <para>Next, we'll take a look at the new <literal>dITStructureRules</literal> instances,
+ which will bring the above name forms to life:</para>
+ <screen>
+ #
+ dITStructureRules: ( 20
+ NAME 'rootSuffixStructure'
+ FORM rootSuffixForm )
+ #
+ dITStructureRules: ( 21
+ NAME 'ouStructure'
+ FORM ouForm
+ SUP ( 20 21 ) )
+ #
+ dITStructureRules: ( 22
+ NAME 'accountStructure'
+ FORM accountForm
+ SUP 21 )
+ #
+ dITStructureRules: ( 23
+ NAME 'groupStructure'
+ FORM groupForm
+ SUP 21 )</screen>
+ <para>From these rules, one can begin to perceive an abstract DIT structure,
+ defined by the incrementing -- and hierarchically-significant -- integer
+ identifiers, each of which reflect the following respective conditions:</para>
+ <itemizedlist>
+ <listitem><para>Given the absence of other entries, the introduction of an entry
+ bearing the <literal>domain</literal> STRUCTURAL class and <literal>dc</literal> RDN
+ attribute signifies the start of the administrative area, or the start of the "chain
+ of enforced rules"</para>
+ <para>When added, this entry SHOULD bear a <literal>governingStructureRule</literal>
+ integer identifier of 20</para></listitem>
+ <listitem><para>Given the introduction of an entry, positioned directly subordinate to
+ the root suffix and bearing the <literal>organizationalUnit</literal> STRUCTURAL
+ class and <literal>ou</literal> RDN attribute, the entry is accepted</para>
+ <para>When added, this entry SHOULD bear a <literal>governingStructureRule</literal>
+ integer identifier of 21, the subordinate structure rule of its superior structure
+ rule, 20</para></listitem>
+ <listitem><para>Given the introduction of any additional <literal>organizationalUnit</literal>
+ entries, whether descending directly from the root suffix, OR if subordinate to other
+ <literal>organizationalUnit</literal> entries in "nested" fashion, the entry is accepted
+ by rite of structure rule recursion</para>
+ <para>When added, this entry SHOULD also bear a <literal>governingStructureRule</literal>
+ integer identifier of 21, as with the previous case</para></listitem>
+ <listitem><para>Given the introduction of an entry, positioned directly subordinate to any
+ <literal>organizationalUnit</literal> entry presently governed by DIT structure rule 21
+ and bearing the <literal>inetOrgPerson</literal> STRUCTURAL class and <literal>uid</literal>
+ RDN attribute, the entry is accepted</para>
+ <para>When added, this entry SHOULD bear a <literal>governingStructureRule</literal> integer
+ identifier of 22</para></listitem>
+ <listitem><para>Given the introduction of an entry, positioned directly subordinate to any
+ <literal>organizationalUnit</literal> entry presently governed by DIT structure rule 21
+ and bearing the <literal>groupOfNames</literal> STRUCTURAL class and <literal>cn</literal>
+ RDN attribute, the entry is accepted</para>
+ <para>When added, this entry SHOULD bear a <literal>governingStructureRule</literal> integer identifier
+ of 23</para></listitem>
+ </itemizedlist>
+ <para>Next, we'll be creating the initial portions of the governed DIT using <command>ldapmodify</command>,
+ and periodically checking the results with <command>ldapsearch</command> along the way.</para>
+ <note>In cases where changes are made in this section, the root DN user (<literal>cn=Directory Manager</literal>)
+ is purposely used. This is simply to demonstrate that no user, regardless of privilege, can "bypass" or
+ otherwise violate DIT structure rules in force.</note>
+ <screen>
+ $ ldapmodify -w password \
+ -D "cn=Directory Manager" \
+ -h opendj.example.com
+
+ dn: dc=example,dc=com
+ changetype: add
+ objectClass: domain
+
+ Processing ADD request for dc=example,dc=com
+ ADD operation successful for DN dc=example,dc=com
+
+ dn: ou=Accounts,dc=example,dc=com
+ changetype: add
+ objectClass: organizationalUnit
+
+ Processing ADD request for ou=Accounts,dc=example,dc=com
+ ADD operation successful for DN ou=Accounts,dc=example,dc=com
+
+ dn: ou=Consultants,ou=Accounts,dc=example,dc=com
+ changetype: add
+ objectClass: organizationalUnit
+
+ Processing ADD request for ou=Consultants,dc=example,dc=com
+ ADD operation successful for DN ou=Consultants,dc=example,dc=com</screen>
+ <para>So far, so good. What we've just done is create the initial structure of
+ our DIT, and in doing so we've confirmed the DIT structure rules do not seem
+ to be interfering.</para>
+ <para>But, let's stop for now and check our work. We want to see the DIT structure
+ rules that are <emphasis>actively</emphasis> governing our entries. To do this, we
+ need only perform a simple anonymous LDAP search:</para>
+ <screen>
+ $ ldapsearch -h opendj.example.com \
+ -b dc=example,dc=com \
+ "(objectClass=*)" \
+ governingStructureRule
+
+ dn: dc=example,dc=com
+ governingStructureRule: 20
+
+ dn: ou=Accounts,dc=example,dc=com
+ governingStructureRule: 21
+
+ dn: ou=Consultants,ou=Accounts,dc=example,dc=com
+ governingStructureRule: 21</screen>
+ <para>This proves the following:</para>
+ <itemizedlist>
+ <listitem>Rule 20, the <literal>rootSuffixStructure</literal> definition,
+ represents the start of the structure chain</listitem>
+ <listitem>Rule 21, the <literal>ouStructure</literal> definition, represents
+ the permitted subordinate naming context below entries governed by the
+ <literal>rootSuffixStructure</literal> rule</listitem>
+ <listitem>Rule 21, as it supports recursion by nature, allows <literal>organizationalUnit</literal>
+ entries to reside <emphasis>within </emphasis> <literal>organizationalUnit</literal> entries, thus
+ allowing categorical organizational structures to exist</listitem>
+ </itemizedlist>
+ <para>Let's see what happens when we attempt to add an entry bearing an unauthorized RDN syntax.</para>
+ <screen>
+ $ ldapmodify -w password \
+ -D "cn=Directory Manager"\
+ -h opendj.example.com
+
+ dn: mail=user@example.com,ou=Consultants,ou=Accounts,dc=example,dc=com
+ changetype: add
+ objectClass: inetOrgPerson
+ cn: User Person
+ sn: Person
+
+ Processing ADD request for
+ mail=user@example.com,ou=Consultants,ou=Accounts,dc=example,dc=com
+ The LDAP modify request failed: 65 (Object Class Violation)
+ Additional Information: Entry
+ mail=user@example.com,ou=Consultants,ou=Accounts,dc=example,dc=com violates
+ the Directory Server schema configuration because its RDN does not contain
+ attribute uid that is required by name form accountForm</screen>
+ <para>Good, the DIT structure rule in question seems to work in preventing bogus RDNs.
+ Now let's continue with entries that are expected to work.</para>
+ <screen>
+ $ ldapmodify -w password \
+ -D "cn=Directory Manager" \
+ -h opendj.example.com
+
+ dn: uid=userPerson,ou=Consultants,ou=Accounts,dc=example,dc=com
+ changetype: add
+ objectClass: inetOrgPerson
+ sn: Person
+ cn: User Person
+
+ Processing ADD request for uid=userPerson,ou=Consultants,ou=Accounts,dc=example,dc=com
+ ADD operation successful for DN uid=userPerson,ou=Consultants,ou=Accounts,dc=example,dc=com
+
+ dn: ou=Groups,dc=example,dc=com
+ changetype: add
+ objectClass: organizationalUnit
+
+ Processing ADD request for ou=Groups,dc=example,dc=com
+ ADD operation successful for DN ou=Groups,dc=example,dc=com
+
+ dn: ou=Corporate,ou=Groups,dc=example,dc=com
+ changetype: add
+ objectClass: organizationalUnit
+
+ Processing ADD request for ou=Corporate,ou=Groups,dc=example,dc=com
+ ADD operation successful for DN ou=Corporate,ou=Groups,dc=example,dc=com
+
+ dn: ou=Infrastructure,ou=Groups,dc=example,dc=com
+ changetype: add
+ objectClass: organizationalUnit
+
+ Processing ADD request for ou=Infrastructure,ou=Groups,dc=example,dc=com
+ ADD operation successful for DN ou=Infrastructure,ou=Groups,dc=example,dc=com
+
+ dn: cn=Abuse Mail,ou=Infrastructure,ou=Groups,dc=example,dc=com
+ changetype: add
+ objectClass: groupOfNames
+
+ Processing ADD request for cn=Abuse Mail,ou=Infrastructure,ou=Groups,dc=example,dc=com
+ ADD operation successful for DN cn=Abuse Mail,ou=Infrastructure,ou=Groups,dc=example,dc=com</screen>
+ <para>Again, let's check our work (omitting the contents of the previous LDAP search):</para>
+ <screen>
+ $ ldapsearch -h opendj.example.com \
+ -b dc=example,dc=com \
+ "(objectClass=*)" \
+ governingStructureRule
+
+ dn: uid=userPerson,ou=Consultants,ou=Accounts,dc=example,dc=com
+ governingStructureRule: 22
+
+ dn: ou=Groups,dc=example,dc=com
+ governingStructureRule: 21
+
+ dn: ou=Corporate,ou=Groups,dc=example,dc=com
+ governingStructureRule: 21
+
+ dn: ou=Infrastructure,ou=Groups,dc=example,dc=com
+ governingStructureRule: 21
+
+ dn: cn=Abuse Mail,ou=Infrastructure,ou=Groups,dc=example,dc=com
+ governingStructureRule: 23</screen>
+ <para>So, what did we learn?</para>
+ <itemizedlist>
+ <listitem><literal>ouStructure</literal> rule 21 continues to allow recursive
+ <literal>organizationalUnit</literal> entries, so long as they ultimately extend
+ from the <literal>rootSuffixStructure</literal> superior structure (ancestor)
+ rule 20, <emphasis>or</emphasis> another such entry governed by rule 21</listitem>
+ <listitem><literal>accountStructure</literal> rule 22 is correctly governing
+ entries bearing the <literal>inetOrgPerson</literal> STRUCTURAL class found
+ within an <literal>organizationalUnit</literal> entry (superior structure rule
+ 21)</listitem>
+ <listitem><literal>groupStructure</literal> rule 23 is correctly governing entries
+ bearing the <literal>groupOfNames</literal> STRUCTURAL class found within an
+ <literal>organizationalUnit</literal> entry (superior structure rule 21)</listitem>
+ </itemizedlist>
+ <para>DIT structure rules are extremely powerful. When properly planned and implemented,
+ they can greatly aid in the formation of clean and orderly directory structures without
+ the need for additional ACIs.</para>
+ </section>
+ <section id="dsr-impl-preexist-dit-schema">
+ <title>Considerations Relating To The Implementation Of DIT Structure Rules In
+ An Established DIT</title>
+ <para>Because DIT structure rules do not influence preexisting entries, even those
+ in violation of those rules, this presents a potential pain-point regarding the
+ restoration of content that (in some way) predates the incorporation of those DIT
+ structure rules. This situation may apply following a disaster-triggered reload of
+ data, or when using this data to "seed" a new DSA being built in the topology.</para>
+ <para>If DIT structure rules are already applied to the DSA in question, but data has
+ NOT yet been loaded, the DIT structure rules in question will consider ANY data to be
+ "new" regardless of its true chronological age.</para>
+ <para>If violations are perceived, this will result in errors during the incorporation
+ of that data. This can be confusing to administrators if that same data exists as
+ expected on other DSAs -- even those with effectively identical configurations.</para>
+ <para>When introducing DIT structure rules to an established (preexisting) DIT, it is
+ strongly recommended that separate load-tests be conducted on a disposable system or
+ virtual image that is under the governance of all planned DIT structure rules. This
+ will allow accurate simulation of new in-topology server builds, or rebuilds of
+ preexisting servers that have suffered a malfunction of some kind, or have been
+ rebuilt due to upgrade or other reasons.</para>
+ </section>
+ <section id="dsr-subentries-schema">
+ <title>Considerations For Collective Attribute Subentries</title>
+ <para>DIT structure rules apply not only to standard entries as demonstrated in the
+ previous section, but also to subentries -- entries that bear the <literal>subentry</literal>
+ STRUCTURAL class defined in <link xlink:href="http://tools.ietf.org/html/rfc3672#section-2.4" xlink:show="new">
+ <citetitle>Section 2.4 of RFC 3672</citetitle></link>.</para>
+ <para>In cases where a directory server employs DIT structure rules in addition
+ to collective attributes, it is necessary to implement a new <literal>dITStructureRules</literal>
+ definition: one that enforces a suitable RDN attribute type (such as <literal>cn</literal>)
+ for subentries, while taking into account the superior structure rule(s) involved.</para>
+ <para>To begin, as was done in the previous section, a nameForms definition is required first.</para>
+ <screen>
+ nameForms: ( 1.3.6.1.4.1.56521.999.2.7.5
+ NAME 'subentryForm'
+ OC subentry
+ MUST cn )</screen>
+ <para>Here, we are stating that any entry bearing the <literal>subentry</literal>
+ STRUCTURAL class MUST ONLY utilize the <literal>cn</literal> attribute type for
+ its RDN, as it represents the most common naming strategy for subentries.</para>
+ <para>Next, we need to create the DIT structure rule, but first we need to identify
+ the appropriate superior integer identifiers for the SUP clause.</para>
+ <para>Determining these identifiers is a simple matter. First off, subentries are never
+ created below entries that are not parents themselves (or expected to be parents). In
+ the spirit of the previous section, this allows us to strike two (2) candidates from
+ the list: <literal>inetOrgPerson</literal> entries (accounts), and <literal>groupOfNames</literal>
+ entries (groups).</para>
+ <para>This leaves <literal>domain</literal> (20) and <literal>organizationalUnit</literal>
+ (21) entries. Thus:</para>
+ <screen>
+ dITStructureRules: ( 24
+ NAME 'subentryStructure'
+ FORM subentryForm
+ SUP ( 20 21 ) )</screen>
+ <para>Because subentries themselves do not allow for subordinate entries, we need
+ not worry about rule recursion in this instance.</para>
+ <para>When implemented (and with respect to the parameters of the previous subsection),
+ the definitions defined in this subsection will correctly allow for the addition of
+ entries bearing the <literal>subentry</literal> STRUCTURAL class, thus allowing use
+ of dependent constructs, such as collective attributes, to be used unfettered.</para>
+ </section>
+ <section id="aci-vs-dsr-schema">
+ <title>ACIs Vs. DIT Structure Rules</title>
+ <para>Some LDAP implementations on the market today offer no support for DIT structure
+ rules. A common workaround for this is the use of ACIs to enforce specific naming
+ conventions for entries. While OpenDJ supports this technique just the same, there
+ are potential caveats.</para>
+ <para>Use of ACIs to enforce such rules can be bypassed by users with sufficient access
+ privileges. DIT structure rules, on the other hand, are defined in the schema, which
+ conceptually exists at a lower and more fundamental level than ACIs. As such, no user can
+ bypass a DIT structure rule using conventional means -- not even the root DN.</para>
+ <para>There is also the classic argument that use of ACIs to effect "behavioral changes"
+ in this manner is contrary to the very intent of ACIs. Because DIT structure rules are
+ essentially immutable and do not discriminate the origin of any request, they resemble
+ configuration directives in practice more so than an expression of privilege.</para>
+ <para>The argument against ACIs in this context gains additional momentum when one
+ considers the innate risk of altering ACIs for any reason, as even the slightest
+ misstep can deny critical functionality or, worse, expose data.</para>
+ </section>
+ </section>
</chapter>
--
Gitblit v1.10.0