It is a frequent problem for AD and many other drivers that the schema of the target application does not match the schema of eDirectory. In Active Directory in particular, the use of multi-valued attributes, while supported, tends to be the exception rather than the rule. eDirectory tends in the opposite direction.
A major challenge of AD drivers is that AD’s behavior when an attribute does not meet the schema requirements is that it acts much like a database – it treats a directory update like an atomic database operation. If anything is wrong, everything is rejected. For that reason, often users complain that a percentage of their users did not sync.
The most common example is usually the “Description” attribute, which in eDirectory is multi-valued, and people often fill it with notes about what changes they have manually made to eDirectory objects. By default this is mapped to description in AD, but this is a single-valued attribute. So every user who has more than one value in Description in eDirectory fails to sync anything to AD. And often, 1 out of 250 users are in this state.
Nothing is more frustrating to the end client than what appears to be inconsistent and unpredictable behavior. Most of the reactions I hear to this are similar to, “I guess IDM isn’t really ready for primetime”. Even when we as directory consultants identify the root cause, they insist that the system “just work”.
Now we could play whack-a-mole with these attributes, fixing them one at a time, which is what I used to do. But with IDM 3.5 and some of the new tokens it became possible to read the driver’s settings and take appropriate actions, which is what this policy does.
The requirement is that you actually import the schema from the application for this to work properly. The AD driver delivered functionality has an early AD schema built-in, but if the client is using a later “functional level” of the domain or forest, or if they have extended the schema with Microsoft or third party directory enabled applications, those schema extensions should be imported using the schema policy’s “Import Application Schema” capability. NOTE: Not all drivers support the <query-schema> command, most notably, eDirectory drivers do not.
The schema gets stored as an XML document in the attribute DirXML-ApplicationSchema on the driver object. This rule will read that into a driver scoped node-set variable (since it is static data) if it is not already populated; this means it should only be read in once.
This rule should sit in the Output Transformation so it can operate in the application name space after the schema map policy has been applied. The rule will iterate through each attribute that is in the current command being sent to the connected system and retrieve the attribute name. It then looks up whether that attribute is single or multi-valued from the application schema; if the attribute is single valued, the first value being sent to Active Directory will be saved in a variable, the value stripped and replaced with only the single value.
The rule works as follows:
- Optional: Read the application schema from the driver set if it is not already there
- Iterate through the command document, for each attr-name you find:
- Get the attribute definition from the attribute schema
- Get the value of the multi-valued flag from the attribute
- If the attribute is single-valued
- Get the first value using the operation attribute token
- Strip all the values
- Set the value of the attribute using the set destination attribute token
The cool thing here is that we read the application schema only once, after that we operate on the node set using XPATH to decide what to do, making this a very efficient memory only operation.
It is important to note that in the AD schema, some attribute names are associated with inherited classes; for example, you might inherit telephoneNumber from person and the fact that it is OK for a user to have a telephoneNumber is implied because user is defined as inheriting from person. This means you have to find the attribute wherever it is in the application schema document, not just underneath the class.
<rule> <description>[CIS] Handle Multi-to-single valued conversions</description> <comment xml:space="preserve">Generic Rule which reads the application schema from AD and determines if it needs to take only the first value from a multi-valued eDirectory attribute </comment> <conditions> <or> <if-operation mode="case" op="equal">modify</if-operation> <if-operation mode="case" op="equal">add</if-operation> </or> </conditions> <actions> <do-if> <arg-conditions> <and> <if-local-variable name="APP-SCHEMA" op="not-available"/> </and> </arg-conditions> <arg-actions> <do-set-local-variable name="APP-SCHEMA" scope="driver"> <arg-node-set> <token-xml-parse notrace="true"> <token-base64-decode notrace="true"> <token-src-attr name="DirXML-ApplicationSchema" notrace="true"> <arg-dn> <token-global-variable name="dirxml.auto.driverdn"/> </arg-dn> </token-src-attr> </token-base64-decode> </token-xml-parse> </arg-node-set> </do-set-local-variable> </arg-actions> <arg-actions/> </do-if> <do-for-each> <arg-node-set> <token-xpath expression=".//@attr-name"/> </arg-node-set> <arg-actions> <do-set-local-variable name="CLASS" scope="policy"> <arg-string> <token-class-name/> </arg-string> </do-set-local-variable> <do-set-local-variable name="ATTR-DEF" notrace="true" scope="policy"> <arg-node-set> <token-xpath expression="$APP-SCHEMA/schema-def/class-def/attr-def[@attr-name=$current-node]"/> </arg-node-set> </do-set-local-variable> <do-set-local-variable name="MULTI-VALUED" scope="policy"> <arg-string> <token-xpath expression="$ATTR-DEF/@multi-valued"/> </arg-string> </do-set-local-variable> <do-if> <arg-conditions> <and> <if-local-variable mode="nocase" name="MULTI-VALUED" op="equal">false</if-local-variable> </and> </arg-conditions> <arg-actions> <do-set-local-variable name="VALUE" scope="policy"> <arg-string> <token-op-attr name="$current-node$"/> </arg-string> </do-set-local-variable> <do-strip-op-attr name="$current-node$"/> <do-set-dest-attr-value name="$current-node$"> <arg-value> <token-local-variable name="VALUE"/> </arg-value> </do-set-dest-attr-value> </arg-actions> <arg-actions/> </do-if> </arg-actions> </actions> </rule>