Problem

In the article http://www.novell.com/coolsolutions/tip/19039.html I recommended caution when using the Veto action. The care I suggested revolved around specifying an object class for the event. Like User or Group, since you could quite easily veto the driver startup, if you vetoed indiscriminatly. This is what we in the industry call a “Whoopsee” moment. How many people has this happened too? (I recall two or three from the forums, and I know I ran into it as well a few years ago.)

Then in article http://www.novell.com/communities/node/1858/more-about-veto-command-scoping-events I talked about scoping Delete events. In Active Directory, the delete event comes across the driver, after the object is actually gone, so the object class is lost already. If you had said, “if operation is delete and object class is user” – your rule would never fire.

It turns out you need to exercise similar care when vetoing deletes in Lotus Notes/Domino.

The delete event comes across looking as follows in trace:

<nds dtdversion="2.0" ndsversion="8.x">
  <source>
    <product build="20070918_0802 " instance="Notes" version="3.5.1">Identity Manager Driver for Lotus Notes</product>
    <contact>Novell, Inc.</contact>
  </source>
  <input>
    <delete class-name="Unknown" event-id="95A0E4DB580BA8F78525740A00661234 - 1205348266937">
      <association state="associated">95A0E4DB580BA8F78525740A00661234</association>
    </delete>
  </input>
</nds>

When you delete an object in Notes, and there is no Object class value in the document, the object class is available for events coming on the Publisher channel from Lotus Notes – but the class is actually set to Unknown. This delete process for Notes is different from the Active Directory delete.

As I was writing this article, I noticed that Perry Nuffer got the following article on this topic published at:

http://www.novell.com/communities/node/4165/exploring-unknown-class-lotus-notes-driver

He basically makes a similar point, explaining why in Lotus Notes, a deleted user will come across with the Unknown object class. This is a very nicely timed publication. I can explain why something did not work, and how to work around and fix it, while Perry can explain why it behaves in this seemingly inexplicable manner, from a lower level than I know about.

This falls into my general discussion about driver configurations. I would really like to see more explanation of why a driver does something in the rules and stylesheets, beyond simple descriptions of what it does.

I try to document drivers I work on, using the Description field for each rule, with what I did, and if there was a reason why I did it. I most especially focus on what I tried and failed, and why it failed. This way I save myself time when I revisit it a day, a month, or a year later – my train of thought is documented.

One area where I couldn’t really do this was in the filter, but the new Designer and iManager snapins look to be adding support for a comment on each line of the Filter policy. This will be a great new feature for explaining why we are synchronizing an attribute, and why we chose to make the Merge Authority some value, or turned off Optimize modify. That’s useful information that until now has been very hard to store with the settings themselves.

Back to our problem at hand then … if your rule is typical of what I would write and suggest, then it is probably something like this example:

<rule>
  <description>Convert Deletes in Lotus Notes to remove association in IDV</description>
  <comment xml:space="preserve">Delete in Notes means remove association in IDV and disable the user in IDV. Take note that the class must be User so we do not veto too many other things. It is good to scope things.</comment>
  <conditions>
  <and>
    <if-class-name mode="nocase" op="equal">User</if-class-name>
    <if-operation op="equal">delete</if-operation>
  </and>
  </conditions>
  <actions>
  <do-add-dest-attr-value direct="true" name="Login Disabled">
    <arg-value type="string">
    <token-text xml:space="preserve">true</token-text>
    </arg-value>
  </do-add-dest-attr-value>
  <do-remove-association direct="true">
    <arg-association>
    <token-association/>
    </arg-association>
  </do-remove-association>
  <do-veto/>
  </actions>
</rule>

Alas, like the Active Directory example in previous articles, this will not work to actually block the delete event. That’s because the test for the object class it is looking for will never evaluate to true, and thus the Veto action will never fire. So, there is nothing to stop the delete from being processed by the Identity Vault.

Solution

The fast, simple, and inelegant way to resolve this is to remove the test for Object class:

  <if-class-name mode="nocase" op="equal">User</if-class-name>

Then the rule will fire every time it sees a deletes coming Lotus Notes and will veto them. However you will need to decide if it is safe to remove the test for Object Class. This might have a consequence if, for example, you want Group deletes to process through to the Identity Vault.

If you want some events to process, and not others, you will probably have to get sneaky and rely on the fact that the event still comes across as Associated, with an association value. This will resolve to an object in the Identity Vault, so we can leverage this tidbit.

Something like this ought to work for you:

<rule>
 <description>Convert Deletes in Lotus Notes to remove association in IDV</description>
 <comment xml:space="preserve">Delete in Notes means remove association in IDV and disable the user in IDV.</comment>
<conditions>
  <and>
    <if-operation op="equal">delete</if-operation>
    <if-association op="associated"/>
  </and>
</conditions>
  <actions>
    <do-set-local-variable name="AssociatedObjectClass" scope="policy">
      <arg-string>
        <token-resolve datastore="dest">
          <arg-association>
            <token-association/>
          </arg-association>
        </token-resolve>
      </arg-string>
    </do-set-local-variable>
    <do-set-local-variable name="AssociatedObjectClass" scope="policy">
      <arg-node-set>
        <token-query>
          <arg-dn>
            <token-local-variable name="AssociatedObjectClass"/>
          </arg-dn>
          <arg-match-attr name="Object Class"/>
          <arg-string>
            <token-text xml:space="preserve">Object Class</token-text>
          </arg-string>
        </token-query>
      </arg-node-set>
    </do-set-local-variable>
    <do-for-each>
      <arg-node-set>
        <token-local-variable name="AssociatedObjectClass"/>
      </arg-node-set>
      <arg-actions>
        <do-if>
          <arg-conditions>
            <and>
              <if-local-variable mode="nocase" name="current-value" op="equal">Group</if-local-variable>
            </and>
          </arg-conditions>
          <arg-actions>
            <do-break/>
          </arg-actions>
          <arg-actions>
            <do-remove-association>
              <arg-association>
                <token-association/>
              </arg-association>
            </do-remove-association>
            <do-veto/>
          </arg-actions>
        </do-if>
      </arg-actions>
    </do-for-each>
    <do-remove-association>
      <arg-association>
        <token-association/>
      </arg-association>
    </do-remove-association>
    <do-veto/>
  </actions>
</rule>

Breaking the rule apart to explain what we are doing, we see the same basic tests in the beginning: is it a delete event, and do we have an associated object?

In this case, we use the Resolve token to go from an association value to a DN in the destination datastore (eDirectory in this case). The association value and its ability to resolve to a distinguished name in eDirectory is how the engine is able to delete the user. This is the case even though the Person in Lotus Notes’ addressbook is already gone and deleted by this point in the process.

Great – now we have a DN for the object being deleted.

1. Use the Query token to pull back that object’s Object Class as a nodeset.

Object Class is actually a list of attributes, usually Top and a few others at a minimum. Each auxillary class you add to a user (the Extensions of this Object in Console One for example) is listed in the Object Class list.

2. Iterate through the nodeset with the for-each token. At each step in the loop, test using an if token, to see if the current-value local variable (automatically set by the for-each token) is equal to the object classes you care about.

In my example, I said if it was a Group object, then break and move on. If it was a User class, then remove the association and veto the event. You can extend this as far as you need to go using more nested if tokens. You can test for the different classes that matter for you, now that you can get back the Object classes of all your objects deleted in Notes.

Hopefully this will help! Enjoy!

0 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 5 (0 votes, average: 0.00 out of 5)
You need to be a registered member to rate this post.
Loading...Loading...
Categories: Uncategorized

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.

Leave a Reply

No Comments
geoffc
By: geoffc
Mar 14, 2008
7:16 am
Reads:
1,041
Score:
Unrated