Change LDAP schema
Learn how to change LDAP schema definitions online and offline.
Description
Estimated time to complete: 30 minutes
LDAP schema definitions determine the kinds of information in the directory and how the information is related. You can update the schema definitions online and offline to change what the directory allows.
Develop and test schema changes online to catch any errors in the updated definitions.
After you validate the schema changes, you can deploy them online with the ldapmodify
command
or offline by copying updated schema files.
Replication replays the LDAP schema changes to other DS servers.
In this use case, you:
-
Understand a scenario where schema changes make sense.
-
Understand how schema changes can require rebuilding indexes.
-
Develop and test schema changes.
-
Practice rolling out schema changes by copying updated schema files.
Goals
In completing this use case, you learn to:
-
Use the
ldapmodify
command to change LDAP schema. -
Rebuild indexes affected by schema changes.
-
Review and remove replication metadata from changed schema files.
Example scenario
One of the directory application owners asks Pat to let their application page through accounts by class of service.
Pat’s directory deployment uses the definition for the classOfService
attribute based on the evaluation profile.
Pat can add an index for the classOfService
attribute,
but wonders if the application owner has additional requirements.
In discussion with the application owner, Pat learns the application owner:
-
Found the class of service attribute can accept any random string value.
They ask Pat if class of service could be restricted to an enumeration of
bronze
,silver
,gold
, andplatinum
. -
Wants a
sharedQuota
attribute like thediskQuota
andmailQuota
attributes.The application owner doesn’t use
sharedQuota
yet, but plans to use it in a few weeks.
Prerequisites
Knowledge
Before you start:
-
Make sure you are familiar with the command line on your operating system.
-
If you’re new to directory services, work through the examples to learn LDAP.
Actions
Before you try this example, install a DS server in evaluation mode.
Tasks
Pat shows the tasks with DS servers in evaluation mode. The order and content of the tasks for production deployments are the same.
Task 1: Add a classOfService
index
The application owner wants to page through accounts by class of service. Class of service has only a few values, and every user account could have the attribute. This is a good match for a big index.
-
Create the index:
$ /path/to/opendj/bin/dsconfig \ create-backend-index \ --backend-name dsEvaluation \ --index-name classOfService \ --set index-type:big-equality \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --no-prompt
-
Build the new index:
$ /path/to/opendj/bin/rebuild-index \ --baseDn dc=example,dc=com \ --index classOfService \ --hostname localhost \ --port 4444 \ --bindDn uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin
Applications can now use the simple paged results control to page through entries with a specified class of service.
Task 2: Develop schema changes
Pat notices the classOfService
attribute has SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
(directory string syntax).
Pat can change the schema definition to use a custom enumeration syntax,
so DS only allows applications to set one of the desired values.
Pat can update the schema again to extend the enumeration as necessary.
Pat also adds a new sharedQuota
attribute modeled on the diskQuota
and mailQuota
attributes.
Pat knows DS rejects malformed online modifications to schema definitions.
Pat develops and tests the schema changes with the ldapmodify
command.
When changing a schema definition, delete the existing value and add the new value as part of the same modification. Otherwise, there’s a window after you delete a definition and before you add the new one where an update could fail or an index could become degraded due to the missing schema definition. The definition you delete must match the definition in the schema LDIF exactly, not including space characters. When you update schema definitions online, DS sets the |
-
Update the schema definitions.
The following example command:
-
Adds an enumeration syntax for class of service
-
Updates the
classOfService
attribute to use the enumeration syntax -
Adds a
sharedQuota
attribute to thecos
object class for class of service attributes
$ /path/to/opendj/bin/ldapmodify \ --hostname localhost \ --port 1636 \ --useSsl \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --bindDN uid=admin \ --bindPassword password << EOF dn: cn=schema changetype: modify add: ldapSyntaxes ldapSyntaxes: ( example-custom-syntax-oid DESC 'Enumeration syntax for class of service' X-ENUM ( 'bronze' 'silver' 'gold' 'platinum' ) X-ORIGIN 'DS Documentation Examples' ) - delete: attributeTypes attributeTypes: ( example-class-of-service-attribute-type NAME 'classOfService' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE userApplications X-ORIGIN 'DS Documentation Examples' ) - add: attributeTypes attributeTypes: ( example-class-of-service-attribute-type NAME 'classOfService' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX example-custom-syntax-oid SINGLE-VALUE USAGE userApplications X-ORIGIN 'DS Documentation Examples' ) - add: attributeTypes attributeTypes: ( example-class-of-service-shared-quota NAME 'sharedQuota' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications X-ORIGIN 'DS Documentation Examples' ) - delete: objectClasses objectClasses: ( example-class-of-service-object-class NAME 'cos' SUP top AUXILIARY MAY ( classOfService $ diskQuota $ mailQuota ) X-ORIGIN 'DS Documentation Examples' ) - add: objectClasses objectClasses: ( example-class-of-service-object-class NAME 'cos' SUP top AUXILIARY MAY ( classOfService $ diskQuota $ mailQuota $ sharedQuota ) X-ORIGIN 'DS Documentation Examples' ) EOF
-
-
Rebuild affected indexes.
This update changes the
classOfService
syntax, so rebuild the index to use the new syntax:$ /path/to/opendj/bin/rebuild-index \ --baseDn dc=example,dc=com \ --index classOfService \ --hostname localhost \ --port 4444 \ --bindDn uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin
If the enumeration syntax changes again, rebuild the
classOfService
index.
Task 3: Save changed schema files
For the production servers, Pat doesn’t change the schema online. Pat keeps schema definition files under source control to track all schema changes.
After modifying the schema online, Pat locates the schema definitions added and changed in the db/schema
LDIF files.
Pat notices DS rewrites the updated LDIF files with one schema definition per line.
Before putting the changed LDIF files under source control, Pat takes care to remove the operational attributes
including the ds-sync-generation-id
and ds-sync-state
attributes.
Using the wrong values for those attributes could break schema replication.
Pat lets DS replication manage the operational attributes.
In Pat’s copies of the LDIF files, the schema definitions are folded for readability. Each line continuation starts with two spaces before a schema element keyword. LDIF continuation consumes the first space. The second space separates the keyword from the preceding text.
Show 60-ds-evaluation-schema.ldif
dn: cn=schema
objectclass: top
objectclass: ldapSubentry
objectclass: subschema
cn: schema
ldapSyntaxes: ( example-custom-syntax-oid
DESC 'Enumeration syntax for class of service'
X-ENUM ( 'bronze' 'silver' 'gold' 'platinum' )
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
attributeTypes: ( example-class-of-service-disk-quota
NAME 'diskQuota'
EQUALITY caseIgnoreMatch
ORDERING caseIgnoreOrderingMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
USAGE userApplications
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
attributeTypes: ( example-class-of-service-mail-quota
NAME 'mailQuota'
EQUALITY caseIgnoreMatch
ORDERING caseIgnoreOrderingMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
USAGE userApplications
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
attributeTypes: ( example-class-of-service-shared-quota
NAME 'sharedQuota'
EQUALITY caseIgnoreMatch
ORDERING caseIgnoreOrderingMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
USAGE userApplications
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
attributeTypes: ( json-attribute-oid
NAME 'json'
EQUALITY caseIgnoreJsonQueryMatch
SYNTAX 1.3.6.1.4.1.36733.2.1.3.1
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
attributeTypes: ( oauth2token-attribute-oid
NAME 'oauth2Token'
EQUALITY caseIgnoreOAuth2TokenQueryMatch
SYNTAX 1.3.6.1.4.1.36733.2.1.3.1
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
attributeTypes: ( jsonToken-attribute-oid
NAME 'jsonToken'
EQUALITY caseIgnoreJsonTokenIDMatch
SYNTAX 1.3.6.1.4.1.36733.2.1.3.1
SINGLE-VALUE
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
attributeTypes: ( example-class-of-service-attribute-type
NAME 'classOfService'
EQUALITY caseIgnoreMatch
ORDERING caseIgnoreOrderingMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX example-custom-syntax-oid
SINGLE-VALUE
USAGE userApplications
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
objectClasses: ( json-object-class-oid
NAME 'jsonObject'
SUP top
AUXILIARY
MAY json
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
objectClasses: ( oauth2token-object-class-oid
NAME 'oauth2TokenObject'
SUP top
AUXILIARY
MAY oauth2Token
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
objectClasses: ( json-token-object-class-oid
NAME 'JsonTokenObject'
SUP top
AUXILIARY
MAY jsonToken
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
objectClasses: ( example-class-of-service-object-class
NAME 'cos'
SUP top
AUXILIARY
MAY ( classOfService $ diskQuota $ mailQuota $ sharedQuota )
X-ORIGIN 'DS Documentation Examples'
X-SCHEMA-FILE '60-ds-evaluation-schema.ldif' )
Show 99-user.ldif
dn: cn=schema
objectclass: top
objectclass: ldapSubentry
objectclass: subschema
cn: schema
Pat also keeps copies of the original DS schema files under source control. When upgrading, Pat compares the original files with the upgraded files and applies any changes to the modified production files as necessary.
Task 4: Deploy changed schema files
To make a schema change in deployment, stop the server, add the custom schema, and restart the server.
-
Prepare to show schema change deployment by setting up two replicated DS directory servers as described in Install DS and Learn replication.
-
Make sure you have local copies of the changed schema definition files:
- 60-ds-evaluation-schema.ldif
-
This file contains the changed schema definitions.
- 99-user.ldif
-
This file removes the replication metadata.
-
Stop a server:
$ /path/to/opendj/bin/stop-ds
-
Add the custom schema files and start the replica:
$ cp 60-ds-evaluation-schema.ldif /path/to/opendj/db/schema/
-
Start the server:
$ /path/to/opendj/bin/start-ds
Replication applies the changes to other servers.
Task 5: Deploy the classOfService
index
Create and build the index on each replica an application uses for searches:
-
Create the index on the first server:
$ /path/to/opendj/bin/dsconfig \ create-backend-index \ --backend-name dsEvaluation \ --index-name classOfService \ --set index-type:big-equality \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin \ --no-prompt
-
Build the new index on the first server:
$ /path/to/opendj/bin/rebuild-index \ --baseDn dc=example,dc=com \ --index classOfService \ --hostname localhost \ --port 4444 \ --bindDn uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/opendj/config/keystore \ --trustStorePassword:file /path/to/opendj/config/keystore.pin
-
Create the index on the second server:
$ /path/to/replica/bin/dsconfig \ create-backend-index \ --backend-name dsEvaluation \ --index-name classOfService \ --set index-type:big-equality \ --hostname localhost \ --port 14444 \ --bindDN uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/replica/config/keystore \ --trustStorePassword:file /path/to/replica/config/keystore.pin \ --no-prompt
-
Build the new index on the second server:
$ /path/to/replica/bin/rebuild-index \ --baseDn dc=example,dc=com \ --index classOfService \ --hostname localhost \ --port 14444 \ --bindDn uid=admin \ --bindPassword password \ --usePkcs12TrustStore /path/to/replica/config/keystore \ --trustStorePassword:file /path/to/replica/config/keystore.pin
The new schema definitions and indexes are ready to use.
Validation
After you deploy the changed schema definitions and classOfService
indexes,
follow these steps to check you can use the updated schema definitions and index.
-
Page through entries with
gold
class of service on the second replica as a user who doesn’t have theunindexed-search
privilege:$ ldapsearch \ --hostname localhost \ --port 11636 \ --useSsl \ --usePkcs12TrustStore /path/to/replica/config/keystore \ --trustStorePassword:file /path/to/replica/config/keystore.pin \ --bindDN uid=kvaughan,ou=People,dc=example,dc=com \ --bindPassword bribery \ --baseDn dc=example,dc=com \ --simplePageSize 5 \ "(classOfService=gold)" \ mail dn: uid=abarnes,ou=People,dc=example,dc=com mail: abarnes@example.com dn: uid=ahall,ou=People,dc=example,dc=com mail: ahall@example.com dn: uid=aknutson,ou=People,dc=example,dc=com mail: aknutson@example.com dn: uid=alutz,ou=People,dc=example,dc=com mail: alutz@example.com dn: uid=ashelton,ou=People,dc=example,dc=com mail: ashelton@example.com Press RETURN to continue
-
Show users can now have
platinum
class of service:$ /path/to/replica/bin/ldapmodify \ --hostname localhost \ --port 11636 \ --useSsl \ --usePkcs12TrustStore /path/to/replica/config/keystore \ --trustStorePassword:file /path/to/replica/config/keystore.pin \ --bindDN uid=admin \ --bindPassword password << EOF dn: uid=bjensen,ou=People,dc=example,dc=com changetype: modify replace: classOfService classOfService: platinum EOF
-
Show users can’t have a random string for class of service:
$ /path/to/replica/bin/ldapmodify \ --hostname localhost \ --port 11636 \ --useSsl \ --usePkcs12TrustStore /path/to/replica/config/keystore \ --trustStorePassword:file /path/to/replica/config/keystore.pin \ --bindDN uid=admin \ --bindPassword password << EOF dn: uid=bjensen,ou=People,dc=example,dc=com changetype: modify replace: classOfService classOfService: custom extended service EOF # The LDAP modify request failed: 21 (Invalid Attribute Syntax) # Additional Information: When attempting to modify entry uid=bjensen,ou=People,dc=example,dc=com to replace the set of values for attribute classOfService, value "custom extended service" was found to be invalid according to the associated syntax: The provided value "custom extended service" cannot be parsed because it is not allowed by enumeration syntax with OID "example-custom-syntax-oid"
What’s next
Pat knows schema definition changes are safe in files under source control. The reasons for the schema changes are not so well known. Pat plans to start and maintain a schema dictionary. The schema dictionary will describe each attribute known to be in use. It will track:
-
Who uses the attribute, including their contact information, and how they use it
-
What data it stores, and who owns the data, including contact information
-
Where the data comes from, especially if it comes from another system
-
When there are maintenance windows for the attribute (for reindexing and so on)
In addition, Pat has more to discuss with the application owner, who asked for the new sharedQuota
attribute.
The diskQuota
and mailQuota
attributes
depend on the classOfService
attribute for their values.
-
How should DS define
sharedQuota
values? -
What should the quotas be for
classOfService: platinum
?