Overview#

These are some DirXML Examples of rules and policies.

Creating A new document from The current Document#

Calling A Custom Java Function From Dirxml#

We show how we did UUID Generation form a driver.

Another example of calling Java Unique Value Finder with Driver

Using the Time Tokens#

Great news!

We no longer need to make Java calls to know what time it is.

Starting with version 3.5, there are two items to help with time.

The Time() token will get the time in most any desired format.

There is also the token-convert-time token

NameExampleDescription
!CTIME1261598953Number of seconds since Midnight, January 1, 1970. (Compatible with eDirectory time syntaxes)
!JTIME1261598953000Number of milliseconds since Midnight, January 1, 1970. (Compatible with Java time)
!FILETIME129060725530000000Number of 100-nanosecond intervals since January 1, 1601 (Compatible with Win32 FILETIME)
!FULL.TIME8:09:13 PM UTCLanguage specific FULL time format.
!LONG.TIME8:09:13 PM UTCLanguage specific LONG time format.
!MEDIUM.TIME8:09:13 PMLanguage specific MEDIUM time format.
!SHORT.TIME8:09 PMLanguage specific SHORT time format.
!FULL.DATEWednesday, December 23, 2009Language specific FULL date format.
!LONG.DATEDecember 23, 2009Language specific LONG date format.
!MEDIUM.DATEDec 23, 2009Language specific MEDIUM date format.
!SHORT.DATE12/23/09Language specific SHORT date format.
!FULL.DATETIMEWednesday, December 23, 2009 8:09:13 PM UTCLanguage specific FULL date/time format.
!LONG.DATETIMEDecember 23, 2009 8:09:13 PM UTCLanguage specific LONG date/time format.
!MEDIUM.DATETIMEDec 23, 2009 8:09:13 PMLanguage specific MEDIUM date/time format.
!SHORT.DATETIME12/23/09 8:09 PMLanguage specific SHORT date/time format.
yyyy-MM-dd-HH:mm:ss Z2009-12-23-22:09:13 +0000Custom time based on Java Token Syntax

The the token-convert-time token can also do offsets from a provided time. This allows a time, like loginExpirationTime, to be set to 90 days as an example. The offset can be specified as any integer number of one of the following:

  • seconds
  • minutes
  • hours
  • days
  • weeks
  • months
  • years

The tokens can also set to any defined time zone and can be language specific

See Geoffrey Carman's Article on Using the Time Tokens in IDM 3.5

Using Expandable GCV Values#

A method to expand values within GCVs without re-writing the driver(s).

SQL Calls From Driver (Publisher Channel)#

Naming as First Initial of First Name#

Client wanted names to be First Initial of First name, first character of Middle Name (if it exist) followed by last name never exceeding 8 characters and using numbers to break a collision.

This will give you a 1 digit counter after an initial collision. If you change change it if you want a counter even when no collisions, then get rid of the first pattern. If you want more than one digit, change the counter digits, and adjust the substring length in the pattern to match. (Thank you Father Ramon)

<do-set-local-variable name="proposed" scope="policy">
  <arg-string>
    <token-substring length="8">
      <token-substring length="1">
        <token-attr name="Given Name"/>
      </token-substring>
      <token-substring length="1">
        <token-attr name="Initials"/>
      </token-substring>
      <token-attr name="Surname"/>
    </token-substring>
  </arg-string>
</do-set-local-variable>
<do-set-op-dest-dn>
  <arg-dn>
    <token-unique-name counter-digits="1" counter-pattern="last" counter-use="always" name="CN" on-unavailable="error">
      <arg-string>
        <token-local-variable name="proposed"/>
      </arg-string>
      <arg-string>
        <token-substring length="7">
          <token-local-variable name="proposed"/>
        </token-substring>
      </arg-string>
    </token-unique-name>
  </arg-dn>
</do-set-op-dest-dn> 

Delete users In 150 Days#

This is a rule from David Gersic using the workorder Driver in IDM 3.5 placed on the Publisher Command Transform. The HR driver takes "employee status == terminated" and changes it to a "account disabled". This rule, then, takes the disable and schedules it to be deleted.

Detect Status message and Send Email#

We have found that this is an almost critical policy set that should be implemented on all IDM systems which might not have any other means to detect these conditions.

Need One Value of a Multi-valued attribute#

We were running into some issues where people had multiple CN values or were named by uniqueID and found several of the "default" policies did not work well with these situations.

As some what obvious solution, once we hit on it was using sourceName we eliminated the multiple values and the bypassed the difficulty of some clients using uniqueID.

Here is a policy to pull one value of a multi-valued attribute.

<rule>
 <conditions>
  <and>
   <if-operation op="equal">modify</if-operation>
   <if-op-attr name="Given Name" op="changing"/>
  </and>
 </conditions>
 <actions>
  <do-set-local-variable name="givenname">
   <arg-node-set>
    <token-op-attr name="Given Name"/>
   </arg-node-set>
   <do-strip-op-attr name="Given Name"/>
   <do-clear-dest-attr-value name="Given Name"/>
   <do-for-each>
    <arg-node-set>
     <token-xpath expression="$givenname[1]"/>
    </arg-node-set>
    <arg-actions>
     <do-add-dest-attr-value name="Given Name">
      <arg-value>
       <token-local-variable name="current-node"/>
      </arg-value>
     </do-add-dest-attr-value>
    </arg-actions>
   </do-for-each>
 </actions>
</rule>

Execute Command Line From Driver#

This is an example using a text driver on Windows that executes a script. It looks like this:
<do-set-local-variable name="runtime-instance">
	<arg-object>
		<token-xpath expression="runtime:getRuntime()"/>
	</arg-object>
	</do-set-local-variable>
	<do-set-local-variable name="cmd-line">
	<arg-string>
		<token-text xml:space="preserve">C:\WINDOWS\system32\cscript.exe</token-text>
		<token-text xml:space="preserve"> </token-text>
		<token-text xml:space="preserve">C:\scripts\Insert_Event.vbs</token-text>
		<token-text xml:space="preserve"> </token-text>
		<token-text xml:space="preserve">TIVOLI</token-text>
		<token-text xml:space="preserve"> </token-text>
		<token-attr name="arzBanknummer"/>
		<token-text xml:space="preserve"> </token-text>
		<token-attr name="arzHostId"/>
		<token-text xml:space="preserve"> </token-text>
		<token-attr name="Surname"/>
		<token-text xml:space="preserve"> </token-text>
		<token-attr name="Given Name"/>
		<token-text xml:space="preserve"> </token-text>
		<token-text xml:space="preserve">MODIFY</token-text>
		<token-text xml:space="preserve"> </token-text>
		<token-text xml:space="preserve">RESR</token-text>
		<token-text xml:space="preserve"> </token-text>
		<token-text xml:space="preserve">"Modifying user properties"</token-text>
	</arg-string>
	</do-set-local-variable>
	<do-trace-message>
	<arg-string>
		<token-local-variable name="cmd-line"/>
	</arg-string>
	</do-trace-message>
	<do-set-local-variable name="process">
	<arg-object>
		<token-xpath expression="runtime:exec($runtime-instance, $cmd-line)"/>
	</arg-object>
	</do-set-local-variable>
Note: You must declare the runtime namespace for the policy:
<policy xmlns:runtime="http://www.novell.com/nxsl/java/java.lang.Runtime">

Query for an OU and retrieve several attributes.#

Place the raw result of the query into a variable of type node-set and then use that variable to get the results for individual values.
<do-set-local-variable name="result">
 <arg-node-set>
  <token-xpath expression='query:search($destQueryProcessor, 
 "subtree", "", "", "Organizational Unit", "OU", $user-locID,
  "L,Telephone Number")'/>
 </arg-node-set>
</do-set-local-variable>
<do-set-local-variable name="result-L">
 <arg-string>
  <token-xpath expression='$result/attr[@attr-name="L"]/value'/>
 </arg-string>
</do-set-local-variable>
<do-set-local-variable name="result-phone">
 <arg-string>
  <token-xpath expression='$result/attr[@attr-name="Telephone Number"]/value'/>
 </arg-string>
</do-set-local-variable>

Creating New Groups based on Multi-Valued Attribute in IDM#

From Novell Cool Solutions: Tip

"I have two rules which read the value of a single-valued attribute, check to see if a group exists with the name of the value that was read, and create the group if necessary.

I need to do the same thing with multi-valued attributes. For example, I would read attribute "MutliValuedAttribute" which contains 3 values, "One" "Two" and "Three". Then I check to see if groups exist named "One", "Two" or "Three", and I create the groups if necessary."

And here's the response from IDM expert Father Ramon ... Solution

This is how I would do it with a single rule rather than two:

 <rule>
   <description>Create MultiValuedAttribute groups that don't exist</description>
   <conditions>
    <and>
     <if-op-attr name="MultiValuedAttribute" op="available"/>
    </and>
   </conditions>
   <actions>
    <do-for-each>
     <arg-node-set>
      <token-op-attr name="MultiValuedAttribute"/>
     </arg-node-set>
     <arg-actions>
      <do-set-local-variable name="desiredGroup" scope="policy">
       <arg-string>
        <token-global-variable name="group-container"/>
        <token-local-variable name="current-node"/>
       </arg-string>
      </do-set-local-variable>
      <do-set-local-variable name="desiredGroupObjectClass" scope="policy">
       <arg-node-set>
        <token-dest-attr name="Object Class">
         <arg-dn>
          <token-local-variable name="desiredGroup"/>
         </arg-dn>
        </token-dest-attr>
       </arg-node-set>
      </do-set-local-variable>
      <do-for-each>
       <arg-node-set>
        <token-xpath expression="$current-node[not($desiredGroupObjectClass = 'Group')]"/>
       </arg-node-set>
       <arg-actions>
        <do-add-dest-object class-name="Group">
         <arg-dn>
          <token-local-variable name="desiredGroup"/>
         </arg-dn>
        </do-add-dest-object>
       </arg-actions>
      </do-for-each>
     </arg-actions>
    </do-for-each>
   </actions>
  </rule>

Set ACLs from IDM#

Here we show how you can set ACL attribute values using DirXML-Script.
<rule>
	<description>Set ACLs (User: add, sync)</description>
	<comment xml:space="preserve">This example runs in a loopback driver.</comment>
	<comment name="author" xml:space="preserve">jim@willeke.com</comment>
	<comment name="version" xml:space="preserve">2</comment>
	<comment name="lastchanged" xml:space="preserve">2011-04-18</comment>
	<conditions>
		<or>
			<if-operation op="equal">add</if-operation>
			<if-operation op="equal">sync</if-operation>
		</or>
	</conditions>
	<actions>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">[Entry Rights]</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">1</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">[All Attributes Rights]</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">3</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">Given Name</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">7</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">Surname</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">7</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">Title</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">7</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">Internet EMail Address</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">7</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">Telephone Number</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">7</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">Language</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">7</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
		<do-add-dest-attr-value name="ACL">
			<arg-value type="structured">
				<arg-component name="protectedName">
					<token-text xml:space="preserve">photo</token-text>
				</arg-component>
				<arg-component name="trustee">
					<token-src-dn/>
				</arg-component>
				<arg-component name="privileges">
					<token-text xml:space="preserve">7</token-text>
				</arg-component>
			</arg-value>
		</do-add-dest-attr-value>
	</actions>
</rule>

For those still stuck in XSL: This is from thanks to Uffe Bager.

<xsl:template match="add[@class-name='user']">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
      <add-attr attr-name="ACL">
        <value type="structured">
          <component name="protectedName">Prot:SSO Entry</component>
      <component name="trustee">\[Self]</component>
        <component name="privileges">15</component>
      </value>
      <value type="structured">
         <component name="protectedName">Prot:SSO Auth</component>
        <component name="trustee">\[Self]</component>
        <component name="privileges">15</component>
      </value>
        <value type="structured">
          <component name="protectedName">Prot:SSO Security Prefs</component>
          <component name="trustee">\[Self]</component>
        <component name="privileges">15</component>
        </value>
        <value type="structured">
          <component name="protectedName">Prot:SSO Entry Checksum</component>
          <component name="trustee">\[Self]</component>
          <component name="privileges">15</component>
         </value>
      <value type="structured">
        <component name="protectedName">Prot:SSO Security Checksum</component>
        <component name="trustee">\[Self]</component>
        <component name="privileges">15</component>
      </value>
    </add-attr>
  </xsl:copy>
</xsl:template> 

Placement In File and Print Tree by Attribute Value#

Based on an attribute in the IDV, you need to place the entry within different OU's.

In this example there is a custom "locationID" attribute with a matching value on the OU. So if there was a OU with LocationID=Sales and we wanted to put all users with the values of "Sales" for a locationID on the user to the OU that possesses the same locationID attribute. Note the OUs may have more than one value for locationID.

<do-set-local-variable name="user-locID">
	<arg-string>
		<token-src-attr name="locationID"/>
	</arg-string>
</do-set-local-variable>
<do-set-local-variable name="placement-ou-dn">
	<arg-string>
		<token-xpath expression='query:search($destQueryProcessor, "~SearchScope~", "", "~SearchBase~", "Organizational Unit", "locationID", $user-locID, "")[1]/@src-dn'/>
	</arg-string>
</do-set-local-variable>
Where "SearchBase" and "SearchScope" are GCVs (set SearchScope to "subtree" and leave SearchBase empty to search the whole tree). This assumes you put the policy on the publisher channel on the destination tree's driver.

To Convert DDMMYY to seconds since 1970#

Input transformation
<policy
xmlns:date="http://www.novell.com/nxsl/java/java.util.Date"
xmlns:format="http://www.novell.com/nxsl/java/java.text.SimpleDateFormat">
     <rule>
         <description>Convert DDMMYY to seconds since 1970</description>
         <conditions/>
         <actions>
             <do-reformat-op-attr name="birthdate">
                 <arg-value type="string">
                     <token-xpath expression="format:format(format:new('yyyy-MM-dd'), date:new($current-value * 1000))"/>
                 </arg-value>
             </do-reformat-op-attr>
         </actions>
     </rule>
</policy> 

Set Login Expiration Time from DDMMYY#

<?xml version="1.0" encoding="UTF-8"?>
<policy xmlns:date="http://www.novell.com/nxsl/java/java.util.Date"
xmlns:format="http://www.novell.com/nxsl/java/java.text.SimpleDateFormat">
 <rule>
   <description>Set expiration time to December 1 of gradyear</description>
   <conditions>
     <and>
        <if-op-attr name="Title" op="available"/>
     </and>
   </conditions>
   <actions>
      <do-set-local-variable name="DateFmt">
         <arg-string>
            <token-text xml:space="preserve">
               12/01/
            </token-text>
            <token-substring length="2" start="2">
            <token-op-attr name="Title"/>
            </token-substring>
         </arg-string>
      </do-set-local-variable>
      <do-set-dest-attr-value name="Login Expiration Time">
         <arg-value type="time">
            <token-xpath expression="round(date:parse($DateFmt)div 1000)"/>
         </arg-value>
      </do-set-dest-attr-value>
      <do-strip-op-attr name="Title"/>
   </actions>
 </rule>
</policy>

Title Case#

So, you finally got a rule that builds a full name but now you want to change the full name to have proper "Title" case.
         <do-reformat-op-attr name="UPPERCASE">
             <arg-value>
                 <token-replace-all regex="\b([a-z])" replace-with="\1">
                         <token-lower-case>
                         <token-local-variable name="current-value"/>
                         </token-lower-case>
                 </token-replace-all>
             </arg-value>
         </do-reformat-op-attr> 

Detect Multiple Matches#

When matching on an attribute and then get multiple instances back, how owuld you detect that there is more than one match?
<do-set-local-variable name="dest-dn">
 <arg-string>
  <token-dest-dn/>
 </arg-string>
</do-set-local-variable>

followed by:

<if-local-variable name="dest-dn" op="equal" mode="regex">\uFFFC|\uFFFD</if-local-variable> 

Remove Association#

<rule>
  <description>User: attr L=single, if true delete from WFT/description>
  <conditions>
    <and>
       <if-class-name mode="nocase" op="equal">User</if-class-name>
       <if-association op="associated"/>
       <if-op-attr mode="nocase" name="L" op="equal">single</if-op-attr>
    </and>
  </conditions>
  <actions>
    <do-remove-association>
        <arg-association>
            <token-association/>
        </arg-association>
    </do-remove-association>
		<do-set-xml-attr name="direct" expression="../remove-association[last()]">
 			<arg-string>
  			<token-text>src</token-text>
 			</arg-string>
		</do-set-xml-attr>     
    <do-delete-dest-object/>
    <do-veto/>
  </actions>
</rule>

Using a GVC for Placement#

<if-src-dn op="not-in-container">~placement-location-in-active-directory~</if-src-dn>

Get and Increment Counter#

The need was to implement a method to ad a new uidNumber to users when they were added by the driver. Novell ships a uamPosixUidNumberInfo and uamPosixGidNumberInfo Aux classes which were applied to the ou=ldapconfig,dc=mycompany,dc=com container.

Also of interest is the "LUM Driver"

When a new user entry was added, the driver;

  • reads the uamPosixUidNumberLastAssigned value on the container defined by the GCV=UIDNumberCounterDN
  • sets a local variable name="lastUserIDUsed" to the value
  • and adds a one (1) to the "lastUserIDUsed" value.
  • Writes the newly incremented value to the uamPosixUidNumberLastAssigned attribute.
  • This value is then used for the uidNumber of the posixAccount aux class which is added to the any new user
entries created.
<policy>
	<rule>
		<description>Get and increment counter</description>
		<comment name="author" xml:space="preserve">jim willeke</comment>
		<comment name="version" xml:space="preserve">120.02</comment>
		<comment name="lastchanged" xml:space="preserve">2006-02-23</comment>
		<conditions>
			<and>
				<if-class-name mode="nocase" op="equal">User</if-class-name>
			</and>
		</conditions>
		<actions>
			<do-set-local-variable name="lastUserIDUsed">
				<arg-string>
					<token-dest-attr name="uamPosixUidNumberLastAssigned">
						<arg-dn>
							<token-global-variable name="UIDNumberCounterDN"/>
						</arg-dn>
					</token-dest-attr>
				</arg-string>
			</do-set-local-variable>
			<do-set-local-variable name="lastUserIDUsed">
				<arg-string>
					<token-xpath expression="$lastUserIDUsed + 1"/>
				</arg-string>
			</do-set-local-variable>
			<do-set-dest-attr-value direct="true" name="uamPosixUidNumberLastAssigned">
				<arg-dn>
					<token-global-variable name="UIDNumberCounterDN"/>
				</arg-dn>
				<arg-value type="string">
					<token-local-variable name="lastUserIDUsed"/>
				</arg-value>
			</do-set-dest-attr-value>
			<do-add-dest-attr-value name="uidNumber">
				<arg-value type="string">
					<token-local-variable name="lastUserIDUsed"/>
				</arg-value>
			</do-add-dest-attr-value>
		</actions>
	</rule>
</policy>

This was used in a more specific policy in IDM Manage Posix Attributes

You may also be interested in our Unique Value Finder Tool.

Check if Group Exists#

<?xml version="1.0" encoding="UTF-8"?>
<policy>
	<rule>
		<description>Query the group to see if it exists</description>
		<conditions>
			<and>
				<if-operation op="equal">add</if-operation>
				<if-attr name="xxx" op="available"/>
			</and>
		</conditions>
		<actions>
			<do-set-local-variable name="wg-dest-dn">
				<arg-string>
					<token-dest-attr class-name="Group" name="CN">
						<arg-dn>
							<token-attr name="xxx"/>
						</arg-dn>
					</token-dest-attr>
				</arg-string>
			</do-set-local-variable>
		</actions>
	</rule>
	<rule>
		<description>Print one trace message if the group exists</description>
		<conditions>
			<and>
				<if-local-variable name="wg-dest-dn" op="available"/>
				<if-local-variable mode="regex" name="wg-dest-dn" op="equal">.*</if-local-variable>
			</and>
		</conditions>
		<actions>
			<do-trace-message level="0">
				<arg-string>
					<token-text xml:space="preserve" xmlns:xml="http://www.w3.org/XML/1998/namespace">The group exists</token-text>
				</arg-string>
			</do-trace-message>
		</actions>
	</rule>
	<rule>
		<description>Print one trace message if the group exists NOT</description>
		<conditions>
			<and>
				<if-local-variable name="wg-dest-dn" op="available"/>
				<if-local-variable mode="regex" name="wg-dest-dn" op="not-equal">.*</if-local-variable>
			</and>
		</conditions>
		<actions>
			<do-trace-message level="0">
				<arg-string>
					<token-text xml:space="preserve" xmlns:xml="http://www.w3.org/XML/1998/namespace">The group doesn't exist</token-text>
				</arg-string>
			</do-trace-message>
		</actions>
	</rule>
</policy>

There is also another way of doing this:

<do-if>
	<arg-conditions>
		<and>
			<if-xpath op=”true”>query:readObject($srcQueryProcessor,”,$lv_objectDN,”,”)</if-xpath>
		</and>
	</arg-conditions>
	<arg-actions>
		<do-set-local-variable name=”lv_objectExist” scope=”policy”>
			<arg-string>
				<token-text xml:space=”preserve”>TRUE</token-text>
			</arg-string>
		</do-set-local-variable>
	</arg-actions>
	<arg-actions>
		<do-set-local-variable name=”lv_objectExist” scope=”policy”>
			<arg-string>
				<token-text xml:space=”preserve”>FALSE</token-text>
			</arg-string>
		</do-set-local-variable>
	</arg-actions>
</do-if>
It will still do a query, but as the query is run via xpath, it's possible to evaluate the result immediately.

Required Attributes#

This policy contains a single rule that enforces the presence of Given Name, Surname, Title, Description and Internet Email Address attributes for User object creation. If any of the attributes are missing, the "veto if operation attribute not available" action stops execution and removes the current operation.

The intent is to block object creation until the required attributes are present, thus making it a good candidate for use in the Creation policy set. It should be positioned within the policy set before any other policies referencing the required attributes.

<?xml version="1.0" encoding="UTF-8"?>
<policy>
	<rule>
		<description>User required attributes:  First/Last Name, Title, Description, Email</description>
		<conditions>
			<or>
				<if-class-name op="equal">User</if-class-name>
			</or>
		</conditions>
		<actions>
			<do-veto-if-op-attr-not-available name="Given Name"/>
			<do-veto-if-op-attr-not-available name="Surname"/>
			<do-veto-if-op-attr-not-available name="Title"/>
			<do-veto-if-op-attr-not-available name="Description"/>
			<do-veto-if-op-attr-not-available name="Internet EMail Address"/>
		</actions>
	</rule>
</policy>

Push-Back#

This policy contains a single rule to "push back" or reset the value of the email attribute - essentially dictating an authoritative source for the attribute via policy.

The conditions test for a user object and if the email attribute is changing - meaning there is an add or modify happening for that attribute.

The action sets the source value back to the value from the destination and strips out the attribute from the current operation. In this particular example, the attribute is referenced in the actions and conditions by the application schema name - a key point for policies defined in the input transformation policy set; although, this policy could be used in any policy set with some minor modifications.

The end result with this policy on the Publisher, is that the identity vault is the authoritative source for the email attribute.

NOTE: this same functionality can be applied via the Filter since the IDM 2.0.1 release.

<?xml version="1.0" encoding="UTF-8"?>
<policy>
	<rule>
		<description>Push back on email changing</description>
		<conditions>
			<and>
				<if-class-name op="equal">User</if-class-name>
				<if-op-attr name="Email" op="changing"/>
			</and>
		</conditions>
		<actions>
			<do-set-src-attr-value name="Email">
				<arg-value type="string">
					<token-dest-attr name="Internet EMail Address"/>
				</arg-value>
			</do-set-src-attr-value>
			<do-strip-op-attr name="Email"/>
		</actions>
	</rule>
</policy>

Placement By Name#

This policy contains four rules that implements a placement policy for User objects based on the first character of the Surname attribute - and generate both a trace message and a custom Nsure Audit event.

The first rule sets up some local variables to be used in the audit event and the trace messages.

The remaining three rules test the leading character of the surname for placement using regular expressions. In the second rule, the match expression "a-i.*" can be read as "starts with a letter between 'a' and 'i', followed by any character zero or more times". By default, regular expression matching is not case sensitive.

The first action sets the destination dn value - the main purpose for a placement policy. The remaining actions output the trace message and generate an audit event using the local variables in the first rule.

This example works specifically for the Publisher channel because the format of the destination dn is suitable for the target destination - eDirectory. This policy could be used on the Subscriber channel, but the dn format should be changed to suit the destination application.

<?xml version="1.0" encoding="UTF-8"?>
<policy>
	<rule>
		<description>Setup Local Variables</description>
		<conditions>
			<and>
				<if-class-name op="equal">User</if-class-name>
			</and>
		</conditions>
		<actions>
			<do-set-local-variable name="LVUsers1">
				<arg-string>
					<token-text xml:space="preserve">User:</token-text>
					<token-op-attr name="cn"/>
					<token-text xml:space="preserve"> added to the </token-text>
					<token-text xml:space="preserve">Training\Users\Active\Users1</token-text>
					<token-text xml:space="preserve"> container</token-text>
				</arg-string>
			</do-set-local-variable>
			<do-set-local-variable name="LVUsers2">
				<arg-string>
					<token-text xml:space="preserve">User:</token-text>
					<token-op-attr name="cn"/>
					<token-text xml:space="preserve"> added to the </token-text>
					<token-text xml:space="preserve">Training\Users\Active\Users2</token-text>
					<token-text xml:space="preserve"> container</token-text>
				</arg-string>
			</do-set-local-variable>
			<do-set-local-variable name="LVUsers3">
				<arg-string>
					<token-text xml:space="preserve">User:</token-text>
					<token-op-attr name="cn"/>
					<token-text xml:space="preserve"> added to the </token-text>
					<token-text xml:space="preserve">Training\Users\Active\Users3</token-text>
					<token-text xml:space="preserve"> container</token-text>
				</arg-string>
			</do-set-local-variable>
		</actions>
	</rule>
	<rule>
		<description>Surname A-I: place in Users1</description>
		<conditions>
			<and>
				<if-class-name op="equal">User</if-class-name>
				<if-op-attr mode="regex" name="Surname" op="equal">[a-i].*</if-op-attr>
			</and>
		</conditions>
		<actions>
			<do-set-op-dest-dn>
				<arg-dn>
					<token-text xml:space="preserve">Training\Users\Active\Users1</token-text>
					<token-text xml:space="preserve">\</token-text>
					<token-op-attr name="CN"/>
				</arg-dn>
			</do-set-op-dest-dn>
			<do-trace-message color="yellow">
				<arg-string>
					<token-local-variable name="LVUsers1"/>
				</arg-string>
			</do-trace-message>
			<do-generate-event id="1000">
				<arg-string name="text1">
					<token-local-variable name="LVUsers1"/>
				</arg-string>
			</do-generate-event>
		</actions>
	</rule>
	<rule>
		<description>Surname J-R: place in Users2</description>
		<conditions>
			<and>
				<if-class-name op="equal">User</if-class-name>
				<if-op-attr mode="regex" name="Surname" op="equal">[j-r].*</if-op-attr>
			</and>
		</conditions>
		<actions>
			<do-set-op-dest-dn>
				<arg-dn>
					<token-text xml:space="preserve">Training\Users\Active\Users2</token-text>
					<token-text xml:space="preserve">\</token-text>
					<token-op-attr name="CN"/>
				</arg-dn>
			</do-set-op-dest-dn>
			<do-trace-message color="yellow">
				<arg-string>
					<token-local-variable name="LVUsers2"/>
				</arg-string>
			</do-trace-message>
			<do-generate-event id="1000">
				<arg-string name="text1">
					<token-local-variable name="LVUsers2"/>
				</arg-string>
			</do-generate-event>
		</actions>
	</rule>
	<rule>
		<description>Surname S-Z: place in Users3</description>
		<conditions>
			<and>
				<if-class-name op="equal">User</if-class-name>
				<if-op-attr mode="regex" name="Surname" op="equal">[s-z].*</if-op-attr>
			</and>
		</conditions>
		<actions>
			<do-set-op-dest-dn>
				<arg-dn>
					<token-text xml:space="preserve">Training\Users\Active\Users3</token-text>
					<token-text xml:space="preserve">\</token-text>
					<token-op-attr name="CN"/>
				</arg-dn>
			</do-set-op-dest-dn>
			<do-trace-message color="yellow">
				<arg-string>
					<token-local-variable name="LVUsers3"/>
				</arg-string>
			</do-trace-message>
			<do-generate-event id="1000">
				<arg-string name="text1">
					<token-local-variable name="LVUsers3"/>
				</arg-string>
			</do-generate-event>
		</actions>
	</rule>
</policy>

Filter events#

This policy contains a single rule used to filter events. Although a contrived sample, this policy is more an example of conditional logic because the single action vetos the current operation when the conditions are met.

The first condition tests if the source dn originates outside a given container, specifically a "Users" container.

The second condition tests if the Login Disaled attribute is true.

The third condition tests if the Title attribute matches a regular expression of ".*consultant|sales.*", which reads as "any character zero or more times, followed by either the word 'consultant' or 'sales', followed by any character zero or more times". Remember that regular exprssions are case-insensitive by default.

Since the conditions are logically or'd, if any are true, the operation is vetoed. So,

  • the operation has to originate from the specified container
  • Login Disabled must NOT be true (account is enabled)
  • the Title must NOT contain 'Consultant' or 'Sales'.
It is designed for the Event Transformation policy set on the Subscriber channel in order to filter events as they come in, but could be modified for use anywhere appropriate. In order to filter events, this policy should be placed first in the chain.
<?xml version="1.0" encoding="UTF-8"?>
<policy>
	<rule>
		<description>Filter events: From Users sub-tree, Users not disabled, no consultants or sales people</description>
		<conditions>
			<or>
				<if-src-dn op="not-in-subtree">Users</if-src-dn>
				<if-attr name="Login Disabled" op="equal">True</if-attr>
				<if-attr mode="regex" name="Title" op="equal">.*consultant|sales.*</if-attr>
			</or>
		</conditions>
		<actions>
			<do-veto/>
		</actions>
	</rule>
</policy>

On Termination, disable user and move to Disabled container#

This policy contains a single rule which disables a user's account and moves them to a disabled container when the Description attribute indicates they are terminated.

The conditions test for an object class of User, an operation of modify and a Description value matching the regular expression "^terminated.*". The regular expression will match a string that "starts with 'terminated' followed by any character zero or more times" (i.e. "Terminated on 02/01/2002 for insubordination") By default, regular expression matches are case-insensitive. The Description attribute is being used as the trigger to disable the user, but the conditions could easily be modified to use any other attribute or value.

The first action, to disable the account, uses "write-ahead" to immediately make the change to the Login Disabled attribute - so the user is disabled as soon as possible.

The second action, to move the user to a disabled container, happens after the current operation so the modify operation can complete before the move takes place.

The policy is written for Publisher channel use because of the use of eDirectory attributes and the DN reference to the disabled container, but the policy could be used on either channel with simple modifications.

The Command Transformation policy set is the recommended location for this policy so that it is last (on Publisher). Ordering within the policy set may be an issue, but this policy could likely be ordered anywhere.

<?xml version="1.0" encoding="UTF-8"?><policy>
	<rule>
		<description>On Termination, disable user and move to Disabled container</description>
		<conditions>
			<and>
				<if-operation op="equal">modify</if-operation>
				<if-class-name op="equal">User</if-class-name>
				<if-op-attr mode="regex" name="Description" op="equal">^terminated.*</if-op-attr>
			</and>
		</conditions>
		<actions>
			<do-set-dest-attr-value direct="true" name="Login Disabled">
				<arg-value type="string">
					<token-text xml:space="preserve">True</token-text>
				</arg-value>
			</do-set-dest-attr-value>
			<do-move-dest-object when="after">
				<arg-dn>
					<token-text xml:space="preserve">Users\Disabled</token-text>
				</arg-dn>
			</do-move-dest-object>
		</actions>
	</rule>
</policy>

Disable User when "Locked By Intruder"#

When a user is locked out of eDirectory because of invalid password attempts, an intruder may continue trying passwords against another system with synchronized passwords. To prevent this, it is possible to disable connected systems' accounts, if they support disabled accounts synchronized with the eDirectory "Login Disabled" attribute.

The first step to implementing this solution involves adding the "Locked By Intruder" attribute to the filter. Do not add it to the Schema Mapping policyset, as we will not be using that type of synchronization to implement this solution. With the attribute under the User class in the filter, set the Subscriber channel synchronization to "Notify" and the Publisher channel synchronization to "Ignore". We will be retrieving the attribute's value and using it before it synchronizes to the remote system.

Add the following rules into a new policy at the top of the Subscriber channel Command Transformation policyset. This can be done in iManager by creating a new policy with Policy Builder and then pasting the following XML in the policy directly ("Edit XML").

Sample Rules

<?xml version="1.0" encoding="UTF-8"?><policy>
    <rule disabled="true">
        <description>DisableADUser</description>
        <conditions>
            <and>
                <if-op-attr name="Locked By Intruder" op="changing-to">true</if-op-attr>
            </and>
        </conditions>
        <actions>
            <do-clone-op-attr dest-name="Login Disabled" src-name="Locked By Intruder"/>
        </actions>
    </rule>

    <rule disabled="true">
        <description>PossiblyEnableADUser</description>
        <conditions>
            <and>
                <if-op-attr name="Locked By Intruder" op="changing"/>
                <if-op-attr name="Locked By Intruder" op="not-equal">true</if-op-attr>
                <if-src-attr name="Login Disabled" op="not-equal">true</if-src-attr>
            </and>
        </conditions>
        <actions>
            <do-add-dest-attr-value name="Login Disabled">
                <arg-value type="string">
                    <token-text xml:space="preserve" xmlns:xml="http://www.w3.org/XML/1998/namespace">false</token-text>;
                </arg-value>
            </do-add-dest-attr-value>
        </actions>
    </rule>
</policy>

Caputre a "Status" message#

<rule>
 <conditions>
  <and>
   <if-operation op="equal">status</if-operation>
   <if-xpath op="true">(@level = 'retry') and contains(., 'niuAccountLockout')</if-xpath>
  </and>
 </conditions>
 <actions>
  <do-status level="error">
   <arg-string>
    <token-text>Whatever message you want</token-text>
   </arg-string>
  </do-status>
  <do-veto/>
 </actions>
</rule> 

facsimile telephone number#

<actions>
  <do-clone-xpath src-expression="$query1" dest-expression=".."/>
  <do-set-local-variable name="instance">
   <arg-node-set>
    <token-xpath
      expression="../instance[last()]"/>
   </arg-node-set>
  </do-set-local-variable>
  <do-for-each>
   <arg-node-set>
    <token-xpath expression="$instance/attr[@attr-name = 'Facsimile
Telephone Number']/value"/>
   </arg-node-set>
   <arg-actions>
    <do-set-local-variable name="faxnum">
     <arg-string>
      <token-xpath
        expression="$current-node/component[@name='faxNumber']"/>
     </arg-string>
    </do-set-local-variable>
    <do-strip-xpath expression="$current-node/node()"/>
    <do-set-local-variable name="temp">
     <arg-string>
      <token-xpath
        expression="$current-node/component[@name='faxNumber']"/>
     </arg-string>
    </do-set-local-variable>
    <do-append-xml-text expression="$current-node">
     <arg-string>
      <token-local-variable name="faxnum"/>
     </arg-string>
    </do-append-xml-text>
    <do-set-xml-attr expression="$current-node" name="type">
     <arg-string>
      <token-text>string</token-text>
     </arg-string>
    </do-set-xml-attr>
   </arg-actions>
  </do-for-each>

  <do-trace-message>
   <arg-string>
    <token-text xml:space="preserve">Output of Facsimile Telephone
Number:</token-text>
    <token-xpath expression="$instance/attr[@attr-name = 'Facsimile
Telephone Number']/value"/>
   </arg-string>
  </do-trace-message>

  <do-append-xml-element expression="$instance" name="attr"/>
  <do-set-xml-attr expression="$instance/attr[last()]" name="attr-name">
   <arg-string>
    <token-text xml:space="preserve">action</token-text>
   </arg-string>
  </do-set-xml-attr>
  <do-append-xml-element expression="$instance/attr[last()]" name="value"/>
  <do-set-xml-attr expression="$instance/attr[last()]/value" name="type">
   <arg-string>
    <token-text xml:space="preserve">string</token-text>
   </arg-string>
  </do-set-xml-attr>
  <do-append-xml-text expression="$instance/attr[last()]/value">
   <arg-string>
    <token-text xml:space="preserve">D</token-text>
   </arg-string>
  </do-append-xml-text>
  <do-strip-xpath expression="../modify"/>
  <do-break/>
</actions> 

Move to Deleted Users#

<?xml version="1.0" encoding="UTF-8"?><policy>
        <description>This policy is being used to change Delete events coming from
                the Person Registry, into Move events submitted to
                 eDirectory.</description>
        <rule>
                <description>Transform deletes to move to disabled container</description>
                <comment xml:space="preserve">This rule looks for Delete events coming
                   from the Person Registry. It takes those events and changes them to Move.
                   The accounts are moved to the container ou=disabled,dc=gsu,dc=edu and the
                   Login Disabled attribute is set to TRUE.
                </comment>
                <comment name="author" xml:space="preserve">Jeff Johnson</comment>
                <comment name="version" xml:space="preserve">1.0</comment>
                <comment name="lastchanged" xml:space="preserve">08-01-05</comment>
                <conditions>
                        <and>
                                <if-operation op="equal">delete</if-operation>
                        </and>
                </conditions>
                <actions>
                        <do-move-dest-object>
                                <arg-dn>
                                        <token-text xml:space="preserve">edu\disabled</token-text>
                                </arg-dn>
                        </do-move-dest-object>
                        <do-set-dest-attr-value class-name="User" name="Login Disabled">
                                <arg-value type="string">
                                        <token-text xml:space="preserve">true</token-text>
                                </arg-value>
                        </do-set-dest-attr-value>
                        <do-strip-xpath expression="self::delete"/>
                </actions>
        </rule>
</policy>

Credits#

Many of these ideas come from the Newsgroup: novell.support.identity-manager.engine-drivers.

We have found this forum to be extremely helpful with the day-to-day work of dealing with Novell's IDM product. We would list all those whom have helped, but we are sure we would leave too many people out. One solution to the problem at hand is worth any number of pages of documentation.

If Novell provided this good of support for the other products, they would be a better Company.

Special thanks to:

  • Father Ramon
  • Jeff Johnson
  • David Gersic
  • namdev@novell.com (all the folks at Omnibond)
  • Jason Elsberry
  • Perry Nuffer

More Information#

There might be more information for this subject on one of the following:

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-49) was last changed on 2013-05-16 09:04 by jim