On the surface this seemed simple. The attribute is mapped in the default driver and after a few minutes of configuration I had thedriver working so that when I set a Login Expiration Time in EDirectory, it immediately synchronized to AD. … More or Less.
No HH:MM:SS in Microsoft.
In Novell’s E-Directory, when you set a “Login Expiration Time” it consists of Year, Month, Day, Hours, Minutes and seconds. When it makes it to the AD system, it is set as “Account Expires at End of:” Year, Month Day.
End of Day PRIOR to what you set in E-Directory:
That’s right, if you set a user’s account Login to expire at 12:43 p.m. on September 17, 2010, it will show up in Microsoft as “Account Expires End of September 16.
So beware of this. You can either “deal with it” or you can add 86400 to the value being sent into AD, advancing the “End of ” time by 24 hours. (86400 is the number of seconds in a day, and Novell’s time syntax is formulated in “Seconds since January 1, 1970.)
I was in hog heaven, right? No. I shortly was notified that when people were being reactivated, (i.e. their login expiration time was cleared in the vault) the expiration time was not being cleared in AD.
Removal of a Login Expiration Time in EDirectory crosses the driver like this:
<nds dtdversion="3.5" ndsversion="8.x"> <source> <product version="18.104.22.16890903 ">DirXML</product> <contact>Novell, Inc.</contact> </source> <input> <modify cached-time="20091228151945.022Z" class-name="User" event-id="IDV-02-DS#20091228151945#1#1" qualified-src-dn="O=data\OU=usr\OU=edu\CN=1234e8" src-dn="\CUSTOMER\data\usr\edu\1234e8" src-entry-id="261785" timestamp="0#0"> <association state="associated">e5b8a6ad8bdc874cbf5df5a570606780</association> <modify-attr attr-name="Login Expiration Time"> <remove-value> <value timestamp="1262012227#2" type="time">1262224500</value> </remove-value> </modify-attr> </modify> </input> </nds>
A Modify event, with “remove value” for the attribute. That would seem sufficient, right? Not when the AD Attribute (accountExpires) does not allow being set to null. It needs to be set to a value that will equal “Account Never Expires.” A simple LDIFDE comparison of two objects in AD showed that a user with an “accountExpires” that is set has some long string value, while one that “never expires” has a “0” (zero) value.
Great… so I modify my SUBSCRIBER Command Transform to include the following rule:
<rule> <description>Expiration Being Removed: Set value to 0</description> <conditions> <and> <if-operation mode="case" op="equal">modify</if-operation> <if-class-name mode="nocase" op="equal">User</if-class-name> <if-op-attr name="Login Expiration Time" op="changing"/> </and> </conditions> <actions> <do-for-each> <arg-node-set> <token-removed-attr name="Login Expiration Time"/> </arg-node-set> <arg-actions> <do-set-dest-attr-value direct="true" name="Login Expiration Time"> <arg-value> <token-text xml:space="preserve">9223372036854775807</token-text> </arg-value> </do-set-dest-attr-value> </arg-actions> </do-for-each> </actions> </rule>
Notice a couple of things: First, the driver can detect the Op-Attr “changing” but it would not detect this event as having an operation attribute of a specific value, so I first test for the change, and then embed for/each loop in the actions.
For each removed attribute, I set the Destination value to Zero. If you look closely, however, you’ll see that the value I set is not ZERO, but 9223372036854775807.
I tried “0” but, since Novell has an output transform rule that converts all Login Expiration Times to Microsoft AD Format, that had the effect of simply CHANGING the accountExpires date to December 31, 1969.
So I looked up what value Microsoft considered equal to “Account Never Expires” and found the above value. Great!! Sent it through, and the accouneExpires time changed to February 7, 2106. Effectively I had removed the expiration time, but this was not elegant. No matter what value I send through, it will be considered some number of seconds since January 1970, and it is converted by the Output Transform rule for “accountExpires” values.
So, it became clear I had to bypass the “standard” Novell Output Transform as it relates to Account Expires…. Or at least as it handles values that I WANT to be sent through “as is” to Microsoft. So, I modified the standard Novell rule, which has no conditions and 1 action, to the following.
<rule> <description>accountExpires: Convert to Active Directory form</description> <comment xml:space="preserve">This rule is modified from Novell standard rules, to function hand in hand with a Subscriber Command Transform rule that sets the "Login Expiration Time" value to a Microsoft recognized number equaling "never". When the "Login Expiration Time" operation Attribute is set to that number, this rule (sub Output Transform) allows the value to pass through directly without time conversion.</comment> <conditions> <and> <if-op-attr mode="nocase" name="accountExpires" op="not-equal">9223372036854775807</if-op-attr> </and> </conditions> <actions> <do-reformat-op-attr name="accountExpires"> <arg-value type="octet"> <token-xpath expression="jadutil:translateEpoch2FileTime($current-value)"/> </arg-value> </do-reformat-op-attr> </actions> </rule>
With that, the system functions as expected. Adding/modifying a Login Expiration Time results in immediate synchronization to AD. Removing the value in E-Directory removes the value in AD and resets the account to “Account Never Expires.”
Disclaimer: As with everything else at NetIQ Cool Solutions, this content is definitely not supported by NetIQ, so Customer Support will not be able to help you if it has any adverse effect on your environment. It just worked for at least one person, and perhaps it will be useful for you too. Be sure to test in a non-production environment.