Using LDAP SchemaSchema
LDAP services are based on X.500 Directory Services,
which are telecommunications standards.
In telecommunications, interoperability is paramount.
Competitors must cooperate to the extent that they use each others' systems.
For directory services, the protocols for exchanging data
and the descriptions of the data are standardized.
LDAP defines schema that describe both
what attributes a given LDAP entry must have and may optionally have,
and also what attribute values can contain and how they can be matched.
Formal schema definitions protect interoperability when many applications
read and write to the same directory service.
Directory data are much easier to share
as long as you understand how to use LDAP schema.
The Administration Guide chapter on
Managing Schema
covers LDAP schema from the server administrator's perspective.
Administrators can update LDAP directory schema.
OpenDJ directory server includes
a large number of standard schema definitions available by default.
Administrators can also adjust how strictly OpenDJ directory server
applies schema definitions.
This chapter covers LDAP schema from the script developer's perspective.
As a script developer, you use the available schema
and accept the server's application of schema when updating directory entries.
In this chapter you will learn how to:
Look up available schemas
Understand what the schemas allow
Understand and resolve errors that arise due to schema violations
Getting Schema InformationSchemaReading definitions
Directory servers publish information about services they provide
as operational attributes of the root DSE.
The root DSE is the entry with an empty string DN, "".
DSE stands for DSA-Specific Entry.
DSA stands for Directory System Agent.
The DSE differs by server, but is generally nearly identical for replicas.
OpenDJ directory server publishes the DN
of the entry holding schema definitions as the value of the attribute
subschemaSubentry
as shown in .
Finding the Schema Entry
Look up the schema DN:
$ ldapsearch --port 1389 --baseDN "" --searchScope base "(&)" subschemaSubentrydn:
subschemaSubentry: cn=schema
By default, the DN for the schema entry is cn=schema.
The schema entry has the following attributes
whose values are schema definitions:
attributeTypesAttribute type definitions describe
attributes of directory entries,
such as givenName or mail.
objectClassesObject class definitions identify
the attribute types that an entry must have, and may have.
Examples of object classes include
person and organizationalUnit.
Object classes inherit from other object classes.
For example, inetOrgPerson inherits
from person.
Object classes are specified as values of an entry's
objectClass attribute.
An object class can be one of the following:
Structural object classes define
the core structure of the entry,
generally representing a real-world object.
By default, OpenDJ directory entries have
a single structural object class
or at least a single line of structural object class inheritance.
The person object class is structural, for example.
Auxiliary object classes define
additional characteristics of entries.
The posixAccount object class is auxiliary, for example.
Abstract object classes define
base characteristics for other object classes to inherit,
and cannot themselves inherit from other object classes.
The top object class from which others inherit
is abstract, for example.
ldapSyntaxes
An attribute syntax constrains
what directory clients can store as attribute values.
matchingRules
A Matching rule determines how the directory server
compares attribute values to assertion values
for LDAP search and LDAP compare operations.
For example, in a search having the filter (uid=bjensen)
the assertion value is bjensen.
nameForms
A name form specifies which attribute can be used
as the relative DN (RDN) for a structural object class.
dITStructureRules
A DIT structure rule defines a relationship
between directory entries by identifying the name form
allowed for subordinate entries of a given superior entry.
Reading an Object Class Schema Definition
The schema entry in OpenDJ directory server is large
because it contains all of the schema definitions.
Filter the results when reading a specific schema definition.
As schema definitions themselves are long strings,
pass the option
to the ldapsearch command when reading one.
The example below reads the definition
for the person object class:
$ ldapsearch \
--port 1389 \
--baseDN "cn=schema" \
--searchScope base \
--dontWrap \
"(&)" \
objectClasses \
| grep \'person\'objectClasses: ( 2.5.6.6 NAME 'person' SUP top STRUCTURAL MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description )
X-ORIGIN 'RFC 4519' )
Notice the use of the object class name in grep \'person\'
to filter search results.
The actual result would not be wrapped.
The object class defines
which attributes an entry of that object class must have
and which attributes the entry may optionally have.
A person entry must have
a cn and an sn attribute.
A person entry may optionally have
userPassword, telephoneNumber,
seeAlso, and description attributes.
To determine definitions of those attributes, read the LDAP schema
as demonstrated in .
Reading Schema Definitions for an Attribute
The following example shows you how to read the schema definition
for the cn attribute:
$ ldapsearch \
--port 1389 \
--baseDN "cn=schema" \
--searchScope base \
--dontWrap \
"(&)" \
attributeTypes \
| grep \'cn\'attributeTypes: ( 2.5.4.3 NAME ( 'cn' 'commonName' ) SUP name X-ORIGIN 'RFC 4519' )
The cn attribute inherits its definition
from the name attribute.
That attribute definition indicates attribute syntax and matching rules
as shown in the following example:
$ ldapsearch \
--port 1389 \
--baseDN "cn=schema" \
--searchScope base \
--dontWrap \
"(&)" \
attributeTypes \
| grep \'name\'attributeTypes: ( 2.5.4.41 NAME 'name' EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} X-ORIGIN 'RFC 4519' )
This means that the server ignores case when matching a common name value.
Use the OID to read the syntax as shown in the following example:
$ ldapsearch \
--port 1389 \
--baseDN "cn=schema" \
--searchScope base \
--dontWrap \
"(&)" \
ldapSyntaxes \
| grep 1.3.6.1.4.1.1466.115.121.1.15ldapSyntaxes: ( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )
Taken together with the information for the name attribute,
the common name attribute value is a Directory String of at most 32,768 characters.
For details about syntaxes, read
RFC 4517, Lightweight Directory Access Protocol (LDAP):
Syntaxes and Matching Rules.
That document describes a Directory String as one or more UTF-8 characters.
Respecting LDAP SchemaSchemaRespecting definitions
For the sake of interoperability and to avoid polluting directory data,
scripts and applications should respect LDAP schema.
In the simplest case,
scripts and applications can use the schemas already defined.
OpenDJ directory server does accept updates to schema definitions
over LDAP while the server is running.
This means that when a new application calls for attributes
that are not yet defined by existing directory schemas,
the directory administrator can easily add them as described in
Updating Directory Schema
as long as the new definitions do not conflict with existing definitions.
General purpose applications handle many different types of data.
Such applications must deal with schema compliance at run time.
Software development kits such as the Java-based OpenDJ LDAP SDK
provide mechanisms for reading schema definitions at run time
and checking whether entry data is valid according to the schema definitions.
Many scripts do not require run time schema checking.
In such cases it is enough properly to handle
schema-related LDAP result codes when writing to the directory:
LDAP result code: 17 (Undefined attribute type)
The requested operation failed because it referenced
an attribute that is not defined in the server schema.
LDAP result code: 18 (Inappropriate matching)
The requested operation failed because it attempted to perform
an inappropriate type of matching against an attribute.
LDAP result code: 20 (Attribute or value exists)
The requested operation failed because it would have resulted in
a conflict with an existing attribute or attribute value in the target entry.
For example, the request tried to add a second value
to a single-valued attribute.
LDAP result code: 21 (Invalid attribute syntax)
The requested operation failed because it violated the syntax
for a specified attribute.
LDAP result code: 34 (Invalid DN syntax)
The requested operation failed because it would have resulted in
an entry with an invalid or malformed DN.
LDAP result code: 64 (Naming violation)
The requested operation failed because it would have violated
the server's naming configuration.
For example, the request did not respect a name form definition.
LDAP result code: 65 (Object class violation)
The requested operation failed because it would have resulted in
an entry that violated the server schema.
For example, the request tried to remove a required attribute,
or tried to add an attribute that is not allowed.
LDAP result code: 69 (Object class mods prohibited)
The requested operation failed because it would have modified]
the object classes associated with an entry in an illegal manner.
When you encounter an error, take the time to read the additional information.
The additional information from OpenDJ directory server often suffices
to allow you to resolve the problem directly.
and
show some common problems that can result from schema violations.
Object Class Violations
A number of schema violations show up as object class violations.
The following request fails to add an undefined attribute.
$ ldapmodify \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
add: undefined
undefined: This attribute is not defined.
Processing MODIFY request for uid=bjensen,ou=People,dc=example,dc=com
MODIFY operation failed
Result Code: 65 (Object Class Violation)
Additional Information: Entry uid=bjensen,ou=People,dc=example,dc=com cannot
be modified because the resulting entry would have violated the server schema:
Entry uid=bjensen,ou=People,dc=example,dc=com violates
the Directory Server schema configuration because
it includes attribute undefined which is not allowed
by any of the objectclasses defined in that entry
The solution in this case is to make sure
that the undefined attribute is defined
and that it is allowed by one of the object classes defined for the entry.
The following request fails to add a second structural object class:
$ ldapmodify \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
add: objectClass
objectClass: organizationalUnit
Processing MODIFY request for uid=bjensen,ou=People,dc=example,dc=com
MODIFY operation failed
Result Code: 65 (Object Class Violation)
Additional Information: Entry uid=bjensen,ou=People,dc=example,dc=com cannot
be modified because the resulting entry would have violated the server schema:
Entry uid=bjensen,ou=People,dc=example,dc=com violates
the Directory Server schema configuration because
it includes multiple conflicting structural objectclasses
inetOrgPerson and organizationalUnit.
Only a single structural objectclass is allowed in an entry
The solution in this case is to define only one structural object class
for the entry.
Either Babs Jensen is a person or an organizational unit, but not both.
Invalid Attribute Syntax
The following request fails to add an empty string as
a common name attribute value.
$ ldapmodify \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
add: cn
cn:
Processing MODIFY request for uid=bjensen,ou=People,dc=example,dc=com
MODIFY operation failed
Result Code: 21 (Invalid Attribute Syntax)
Additional Information: When attempting to modify entry
uid=bjensen,ou=People,dc=example,dc=com to add one or more values
for attribute cn, value "" was found to be invalid
according to the associated syntax:
The operation attempted to assign a zero-length value to an attribute
with the directory string syntax
As mentioned in ,
a Directory String has one or more UTF-8 characters.
Abusing LDAP Schema
Follow the suggestions in
as much as possible.
In particular follow these rules of thumb:
Test with your own copy of OpenDJ directory server
to resolve schema issues before going live.
Adapt your scripts and applications to avoid violating schema definitions.
When existing schemas are not sufficient,
request schema updates to add definitions
that do not conflict with any already in use.
When it is not possible to respect the schema definitions,
you can sometimes work around LDAP schema constraints
without changing OpenDJ directory server configuration.
The schema defines an extensibleObject object class.
The extensibleObject object class is auxiliary.
It effectively allows entries to hold any user attribute,
even attributes that are not defined in the schema.
Working Around Restrictions With ExtensibleObject
The following example adds one attribute that is undefined
and another that is not allowed.
$ ldapmodify \
--port 1389 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery
dn: uid=bjensen,ou=People,dc=example,dc=com
changetype: modify
add: objectClass
objectClass: extensibleObject
-
add: undefined
undefined: This attribute is not defined in the LDAP schema.
-
add: serialNumber
serialNumber: This attribute is not allowed according to the object classes.
Processing MODIFY request for uid=bjensen,ou=People,dc=example,dc=com
MODIFY operation successful for DN uid=bjensen,ou=People,dc=example,dc=com
Use of the extensibleObject object class
opens the door to abuse and can prevent interoperability.
Restrict its use to cases where no better alternative is available.