Using LDAP Schema 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. "Managing Schema" in the Administration Guide 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 Information 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 is an acronym for DSA-Specific Entry. DSA is an acronym 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". Finding the Schema Entry Look up the schema DN: $ ldapsearch --port 1389 --baseDN "" --searchScope base "(&)" subschemaSubentry dn: 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: attributeTypes Attribute type definitions describe attributes of directory entries, such as givenName or mail. objectClasses Object 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 --dontWrap 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". 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.15 ldapSyntaxes: ( 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. That document describes a Directory String as one or more UTF-8 characters. Respecting LDAP Schema 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" in the Administration Guide as long as the new definitions do not conflict with existing definitions. General purpose applications handle many different types of data. Such applications must manage 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. "Object Class Violations" and "Invalid Attribute Syntax" 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 "Reading Schema Definitions for an Attribute", a Directory String has one or more UTF-8 characters. Abusing LDAP Schema Follow the suggestions in "Respecting LDAP Schema" 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. Standard Schema Included With OpenDJ Server OpenDJ directory server provides many standard schema definitions in these LDIF files under /path/to/opendj/config/schema: 00-core.ldif This file contains a core set of attribute type and object class definitions from the following Internet-Drafts, RFCs, and standards: draft-ietf-boreham-numsubordinates draft-findlay-ldap-groupofentries draft-furuseth-ldap-untypedobject draft-good-ldap-changelog draft-ietf-ldup-subentry draft-wahl-ldap-adminaddr RFC 1274 RFC 2079 RFC 2256 RFC 2798 RFC 3045 RFC 3296 RFC 3671 RFC 3672 RFC 4512 RFC 4519 RFC 4523 RFC 4524 RFC 4530 RFC 5020 X.501 01-pwpolicy.ldif This file contains schema definitions from draft-behera-ldap-password-policy (Draft 09), which defines a mechanism for storing password policy information in an LDAP directory server. 02-config.ldif This file contains the attribute type and objectclass definitions for use with the directory server configuration. 03-changelog.ldif This file contains schema definitions from draft-good-ldap-changelog, which defines a mechanism for storing information about changes to directory server data. 03-rfc2713.ldif This file contains schema definitions from RFC 2713, which defines a mechanism for storing serialized Java objects in the directory server. 03-rfc2714.ldif This file contains schema definitions from RFC 2714, which defines a mechanism for storing CORBA objects in the directory server. 03-rfc2739.ldif This file contains schema definitions from RFC 2739, which defines a mechanism for storing calendar and vCard objects in the directory server. Note that the definition in RFC 2739 contains a number of errors, and this schema file has been altered from the standard definition in order to fix a number of those problems. 03-rfc2926.ldif This file contains schema definitions from RFC 2926, which defines a mechanism for mapping between Service Location Protocol (SLP) advertisements and LDAP. 03-rfc3112.ldif This file contains schema definitions from RFC 3112, which defines the authentication password schema. 03-rfc3712.ldif This file contains schema definitions from RFC 3712, which defines a mechanism for storing printer information in the directory server. 03-uddiv3.ldif This file contains schema definitions from RFC 4403, which defines a mechanism for storing UDDIv3 information in the directory server. 04-rfc2307bis.ldif This file contains schema definitions from draft-howard-rfc2307bis, which defines a mechanism for storing naming service information in the directory server. 05-rfc4876.ldif This file contains schema definitions from RFC 4876, which defines a schema for storing Directory User Agent (DUA) profiles and preferences in the directory server. 05-samba.ldif This file contains schema definitions required when storing Samba user accounts in the directory server. 05-solaris.ldif This file contains schema definitions required for Solaris and OpenSolaris LDAP naming services. 06-compat.ldif This file contains the attribute type and objectclass definitions for use with the directory server configuration. Performing LDAP Operations Working With Groups of Entries