Wikis - Page

Troubleshooting GroupWise Driver External User Creation

0 Likes

Recently I was working through an issue with creating external users in a GroupWise system, via the Novell Identity Manager driver for GroupWise.



This looked really straightforward as Perry Nuffer basically posted every thing needed in an article on Cool Solutions:
GW Driver: Address Book and External Users



However when I tried what he suggested, I kept getting strange errors and it just would not work. Finally I figured it out (Skip to the end if you just want to see the solution). I thought it would be worthwhile to work through the process I followed for several reasons. First it demonstrates an approach to troubleshooting this kind of problem. Second by posting the error messages and traces in an article, it means Google will index it, and the next person who runs into this problem will be able to benefit from the work I already put in.



To start with lets talk about external users. In GroupWise (as I understand it, I am still learning about GroupWise) a user, group, External Entity, Distribution List, and other objects need to be stored in a Post Office. Post Offices are contained in Domains.



When you place an object in GroupWise via the GroupWise Identity Manager driver, you need to specify a dest-dn, that is the distinguished name of a destination location. This is a common requirement of all drivers, but in the case of GroupWise the destination is a reference to the Post Office object the user is being placed in.



Thus the dest-dn for a new user would be the DN of the Post Office object as stored in eDirectory. I am told this is just a shortcut for specifying the two GroupWise attributes 50062 which represents the Post Office name and 50035 which represents the Domain name. Well the object in eDirectory stores both pieces of information and thus can be used instead of setting these two attributes. As it turns out, I had trouble doing it the so called long way, of not setting a destination DN and instead setting the two attributes for Domain and Post Office directly on a regular user create.



Now for external users, the difference is that they exist in an external Post Office. Sounds simple so far, but the twist is that there is no eDirectory representation as an object of the external Post Office. If so, how do you reference the non-existant object in a destination DN?



Well turns out you add an XML attribute gw:classification="external" into the <add> event node, via DirXML Script (example code is in the Cool Solutions article) and then you specify the Domain and Post Office via the 50035 and 50062 attributes when you create the External user.



Tried that, and watching in trace, I would get the following error. If you do not know how to find and read DStrace output, please read this truly excellent article on the topic by Fernando Frietas, one of the backline engineers at Novell Technical Support, as it is the best summary on the topic I have seen to date! Thanks again Fernando for the great contribution!
Capturing and Reading Novell Identity Manager Traces



My attempt at the same issue is much less impressive at:
Guide to Reading DSTRACE Output from Identity Manager



but you never know, different eyes will see different things in both articles.



Anyway, here is the error in trace:



[05/12/09 09:13:11.798]:GroupWise ST:GroupWise:      getStatusFromOutputNode>
[05/12/09 09:13:11.801]:GroupWise ST:GroupWise: getStatusFromOutputNode>statusLevel = success
[05/12/09 09:13:11.801]:GroupWise ST:GroupWise: getAssocKeyAndAssociate>
[05/12/09 09:13:11.802]:GroupWise ST:GroupWise: getAssocKeyFromQuery>
[05/12/09 09:13:11.802]:GroupWise ST:GroupWise: getInstanceNodeFromQuery>instanceNode = instance,null,null
[05/12/09 09:13:11.802]:GroupWise ST:GroupWise: getAssocKeyFromInstanceNode>
[05/12/09 09:13:11.803]:GroupWise ST:GroupWise: getAssocKeyFromInstanceNode>attrNode = null
[05/12/09 09:13:11.803]:GroupWise ST:GroupWise: getGroupWiseIDFromQuery>
[05/12/09 09:13:11.803]:GroupWise ST:GroupWise: getInstanceNodeFromQuery>instanceNode = instance,null,null
[05/12/09 09:13:11.804]:GroupWise ST:GroupWise: getGroupWiseIDFromQuery>attrNode = null
[05/12/09 09:13:11.804]:GroupWise ST:GroupWise: getAssocKeyFromInstanceNode>
[05/12/09 09:13:11.804]:GroupWise ST:GroupWise: getAssocKeyFromInstanceNode>attrNode = null
[05/12/09 09:13:11.804]:GroupWise ST:GroupWise: associateWithGroupWise>targetDN = \ACME-LAB-LDAP\corp\acme\americas\Users\Test Contact6
[05/12/09 09:13:11.805]:GroupWise ST:GroupWise: associateWithGroupWise>targetDNDotFormat = Test Contact6.Users.americas.acme.corp
[05/12/09 09:13:11.806]:GroupWise ST:GroupWise: associateWithGroupWise>assocKey = null
[05/12/09 09:13:11.806]:GroupWise ST:GroupWise: associateWithGroupWise>groupWiseID = null
[05/12/09 09:13:11.806]:GroupWise ST:GroupWise: Add Event
[05/12/09 09:13:11.806]:GroupWise ST:GroupWise: class-name = GroupWise External Entity
[05/12/09 09:13:11.807]:GroupWise ST:GroupWise: *** No Post Office ID.
[05/12/09 09:13:11.807]:GroupWise ST:GroupWise: java.lang.Exception: Invalid Post Office or Domain specified: null
at com.novell.gw.dirxml.driver.common.GWengine.processAddEvent(Unknown Source)
at com.novell.gw.dirxml.driver.common.GWengine.execute(Unknown Source)
at com.novell.gw.dirxml.driver.gw.GWsubscriptionShim.execute(Unknown Source)
at com.novell.nds.dirxml.engine.Subscriber.execute(Subscriber.java:447)
at com.novell.nds.dirxml.engine.Subscriber.execute(Subscriber.java:282)
at com.novell.nds.dirxml.engine.Subscriber$AddProcessor.process(Subscriber.java:1395)
at com.novell.nds.dirxml.engine.Subscriber.processEvent(Subscriber.java:1054)
at com.novell.nds.dirxml.engine.Subscriber.processEvents(Subscriber.java:898)
at com.novell.nds.dirxml.engine.Driver.submitTransaction(Driver.java:624)
at com.novell.nds.dirxml.engine.DriverEntry.submitTransaction(DriverEntry.java:1050)
at com.novell.nds.dirxml.engine.DriverEntry.processCachedTransaction(DriverEntry.java:934)
at com.novell.nds.dirxml.engine.DriverEntry.eventLoop(DriverEntry.java:756)
at com.novell.nds.dirxml.engine.DriverEntry.run(DriverEntry.java:561)
at java.lang.Thread.run(Unknown Source)

[05/12/09 09:13:11.810]:GroupWise ST:GroupWise:
*** GroupWise Error: java.lang.Exception: Invalid Post Office or Domain specified: null
[05/12/09 09:13:11.811]:GroupWise ST:GroupWise: Output:



Well yep, I could not specify the dest-dn of a Post Office since it is an external post office, so that is missing, but no matter what I tried, I could not get past the error. The important part of it was this snippet:


[05/12/09 09:13:11.806]:GroupWise ST:GroupWise:      Add Event
[05/12/09 09:13:11.806]:GroupWise ST:GroupWise: class-name = GroupWise External Entity
[05/12/09 09:13:11.807]:GroupWise ST:GroupWise: *** No Post Office ID.
[05/12/09 09:13:11.807]:GroupWise ST:GroupWise: java.lang.Exception: Invalid Post Office or Domain specified: null (Rest of the stack trace cut out for brevity)



Next step I decided was to see what a success was supposed to look like and see what it should have done, maybe there is a clue in how it should look, as to what I was missing.



Here is the same portion of trace, where the driver shim is working on the received XDS document and converting it into native GroupWise actions to perform.




[05/12/09 09:25:52.613]:GroupWise ST:GroupWise:      getStatusFromOutputNode>
[05/12/09 09:25:52.613]:GroupWise ST:GroupWise: getStatusFromOutputNode>statusLevel = success
[05/12/09 09:25:52.613]:GroupWise ST:GroupWise: getAssocKeyAndAssociate>
[05/12/09 09:25:52.614]:GroupWise ST:GroupWise: getAssocKeyFromQuery>
[05/12/09 09:25:52.614]:GroupWise ST:GroupWise: getInstanceNodeFromQuery>instanceNode = instance,null,null
[05/12/09 09:25:52.614]:GroupWise ST:GroupWise: getAssocKeyFromInstanceNode>
[05/12/09 09:25:52.614]:GroupWise ST:GroupWise: getAssocKeyFromInstanceNode>attrNode = null
[05/12/09 09:25:52.615]:GroupWise ST:GroupWise: getGroupWiseIDFromQuery>
[05/12/09 09:25:52.615]:GroupWise ST:GroupWise: getInstanceNodeFromQuery>instanceNode = instance,null,null
[05/12/09 09:25:52.615]:GroupWise ST:GroupWise: getGroupWiseIDFromQuery>attrNode = null
[05/12/09 09:25:52.616]:GroupWise ST:GroupWise: getAssocKeyFromInstanceNode>
[05/12/09 09:25:52.616]:GroupWise ST:GroupWise: getAssocKeyFromInstanceNode>attrNode = null
[05/12/09 09:25:52.616]:GroupWise ST:GroupWise: associateWithGroupWise>targetDN = \ACME-LAB-LDAP\corp\acme\americas\Users\osmith
[05/12/09 09:25:52.617]:GroupWise ST:GroupWise: associateWithGroupWise>targetDNDotFormat = osmith.Users.americas.acme.corp
[05/12/09 09:25:52.617]:GroupWise ST:GroupWise: associateWithGroupWise>assocKey = null
[05/12/09 09:25:52.617]:GroupWise ST:GroupWise: associateWithGroupWise>groupWiseID = null
[05/12/09 09:25:52.618]:GroupWise ST:GroupWise: Add Event
[05/12/09 09:25:52.618]:GroupWise ST:GroupWise: class-name = User
[05/12/09 09:25:52.618]:GroupWise ST:GroupWise: validateParent>targetParentDN = acme\grpwise\ANDPO1
[05/12/09 09:25:52.619]:GroupWise ST:GroupWise: validateParent>targetParentDho = null
[05/12/09 09:25:52.619]:GroupWise ST:GroupWise: validateParent>externalFlag = false
[05/12/09 09:25:52.619]:GroupWise ST:GroupWise: queryNDS>
[05/12/09 09:25:52.620]:GroupWise ST:GroupWise: GWsubscriptionShim.exchangeDocs - Sending query to NDS ...



Here we see the same part that errored before, looks a little bit different.



[05/12/09 09:25:52.618]:GroupWise ST:GroupWise:      Add Event
[05/12/09 09:25:52.618]:GroupWise ST:GroupWise: class-name = User
[05/12/09 09:25:52.618]:GroupWise ST:GroupWise: validateParent>targetParentDN = acme\grpwise\ANDPO1
[05/12/09 09:25:52.619]:GroupWise ST:GroupWise: validateParent>targetParentDho = null
[05/12/09 09:25:52.619]:GroupWise ST:GroupWise: validateParent>externalFlag = false
[05/12/09 09:25:52.619]:GroupWise ST:GroupWise: queryNDS>
[05/12/09 09:25:52.620]:GroupWise ST:GroupWise: GWsubscriptionShim.exchangeDocs - Sending query to NDS



We still get the Add event, class is User, (though above I tried to use GroupWise External Entity, I was getting the same errors with User class objects as well), but this time, we have a targetParentDN of the DN of the object representing the Post Office, as stored in eDirectory, as opposed to as stored within the GroupWise database. (wpdomain.db?). There is the difference, it really did get a destination DN that it could read and process.



Ok, this shows me where the problem is, what it SHOULD look like when it works, and where it is going wrong. While not a lot of new information came out of this, now I know what I want to make work.



Now this got me thinking, why is the setting the Domain and Post Office information not working. Maybe it has something to do with the external aspect of the Post Office and somehow that information is not making it through.



This led me to go read Perry's article again, and I noticed has a very important line that I totally glossed over. I have no really good excuse, as I should have known better, and for the future, there was a dead giveaway that I should have recognized.



He states that you add an XML attribute to the <add> node. That would look something like this in trace;



<add class-name="GroupWise External Entity" event-id="f44276b##0" qualified-src-dn="dc=corp\dc=acme\dc=americas\OU=Users\CN=Test Contact9" src-dn="\ACME-LAB-LDAP\corp\acme\americas\Users\Test Contact9" src-entry-id="34109" timestamp="1242307097#19">



Well whenever you see something in Identity Manager with a colon, like gw: or es: (for ECMAScript) or any other prefix before a colon, you should realize this is probably calling out to something external. This is the clue I missed.



The next item to recall is that if you want to use something external, you really should be sure that it is defined, so the driver knows how to make that external call and deal with it. Usually called Extension calls, which makes sense, extensions via external widgets and moving things.



Where I think I got trapped is that a bunch of these extensions are now defaults in Identity Manager 3.5 and higher. Oh well. Looks like I need to add an extension namespace for gw: which is in the article, I just forgot to do it!



In the <policy> node, you would add an XML Namespace declaration (xmlns:) for gw: that is equal to a URL which would look like:



xmlns:gw="http://www.novell.com/dirxml/gwdriver"


Now in Designer, this is a minor bit more painful than in iManager, as Designer adds a Designer specific XML tag at the beginning of each document, that scrolls the <policy> node way off to the right.



So in Designer, if you went to the Policy object where you were using the gw:classification extension call, you would see the first line look something like;



<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE policy PUBLIC "policy-builder-dtd" "U:\data\programs\designer301\Designer\eclipse\plugins\com.novell.idm.policybuilder_3.0.1.200901050958\DTD\dirxmlscript3.6.dtd"><policy>



As you can see it scrolls all the way to the right. with almost 200 characters of text in the way. Oh well, this is how Designer works, and it is otherwise harmless, so I just grin and bare it all (but with my clothes on?). No wait, grin and beer it. No wait. grin and bear it. Thats what I meant, I find a teddy bear, and tell it all my woes.



Thus when you are done, the first line should look more like:


<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE policy PUBLIC "policy-builder-dtd" "U:\data\programs\designer301\Designer\eclipse\plugins\com.novell.idm.policybuilder_3.0.1.200901050958\DTD\dirxmlscript3.6.dtd"><policy xmlns:gw="http://www.novell.com/dirxml/gwdriver">



In iManager, much of the preamble <!DOCTYPE> node will not be there, and it much easier to see.



In addition, any time you use an XPATH token in Designer, the first button to the right of the text field is the Namespace editor, and you could use that to define the extension name space as well. I prefer to edit the <policy> node by hand, personally, but you are welcome to do it however you like.



Once I added that namespace declaration, trace looked very different! In a good way!



The <add> node now looks like:



<add class-name="GroupWise External Entity" event-id="f44276b##0" gw:classification="external" qualified-src-dn="dc=corp\dc=acme\dc=americas\OU=Users\CN=Test Contact9" src-dn="\ACME-LAB-LDAP\corp\acme\americas\Users\Test Contact9" src-entry-id="34109" timestamp="1242307097#19" xmlns:gw="http://www.novell.com/dirxml/gwdriver">




[05/12/09 10:09:21.877]:GroupWise ST:GroupWise:      Tue May 12 10:09:21 EDT 2009
[05/12/09 10:09:21.877]:GroupWise ST:GroupWise: domain = /grpwise/pridom
[05/12/09 10:09:21.878]:GroupWise ST:GroupWise: ndsEventID = AMERICAS-AD##121352645e8##0
[05/12/09 10:09:21.878]:GroupWise ST:GroupWise: convertToDotFormat>in = \ACME-LAB-LDAP\corp\acme\americas\Users\Test Contact8
[05/12/09 10:09:21.878]:GroupWise ST:GroupWise: convertEscapeSeq>new token = ACME-LAB-LDAP
[05/12/09 10:09:21.879]:GroupWise ST:GroupWise: getSegment>segment = ACME-LAB-LDAP
[05/12/09 10:09:21.879]:GroupWise ST:GroupWise: convertEscapeSeq>new token = corp
[05/12/09 10:09:21.879]:GroupWise ST:GroupWise: getSegment>segment = corp
[05/12/09 10:09:21.879]:GroupWise ST:GroupWise: convertEscapeSeq>new token = acme
[05/12/09 10:09:21.880]:GroupWise ST:GroupWise: getSegment>segment = acme
[05/12/09 10:09:21.880]:GroupWise ST:GroupWise: convertEscapeSeq>new token = americas
[05/12/09 10:09:21.880]:GroupWise ST:GroupWise: getSegment>segment = americas
[05/12/09 10:09:21.881]:GroupWise ST:GroupWise: convertEscapeSeq>new token = Users
[05/12/09 10:09:21.882]:GroupWise ST:GroupWise: getSegment>segment = Users
[05/12/09 10:09:21.882]:GroupWise ST:GroupWise: convertEscapeSeq>new token = Test Contact8
[05/12/09 10:09:21.882]:GroupWise ST:GroupWise: getSegment>segment = Test Contact8
[05/12/09 10:09:21.882]:GroupWise ST:GroupWise: convertToDotFormat>out = Test Contact8.Users.americas.acme.corp
[05/12/09 10:09:21.883]:GroupWise ST:GroupWise: originalEvent = null
[05/12/09 10:09:21.883]:GroupWise ST:GroupWise: classification = external
[05/12/09 10:09:21.883]:GroupWise ST:GroupWise: Add Event
[05/12/09 10:09:21.883]:GroupWise ST:GroupWise: class-name = GroupWise External Entity
[05/12/09 10:09:21.884]:GroupWise ST:GroupWise: validateParent>targetParentDN = null
[05/12/09 10:09:21.884]:GroupWise ST:GroupWise: validateParent>targetParentDho = INTERNET.USERS
[05/12/09 10:09:21.884]:GroupWise ST:GroupWise: validateParent>externalFlag = true
[05/12/09 10:09:21.884]:GroupWise ST:GroupWise: validateLinkToExternalObj>targetDN = null
[05/12/09 10:09:21.885]:GroupWise ST:GroupWise: validateLinkToExternalObj>targetDho = INTERNET.USERS
[05/12/09 10:09:21.885]:GroupWise ST:GroupWise: validateLinkToExternalObj>objAssocKey = null
[05/12/09 10:09:21.885]:GroupWise ST:GroupWise: validateLinkToExternalObj>parentFlag = true
[05/12/09 10:09:21.886]:GroupWise ST:GroupWise: validateLinkToExternalObj>forceParentExternal = true
[05/12/09 10:09:21.886]:GroupWise ST:GroupWise: getObjDN>Object DN = null
[05/12/09 10:09:21.887]:GroupWise ST:GroupWise: validateLinkToExternalObj>gwDN = null
[05/12/09 10:09:21.887]:GroupWise ST:GroupWise: validateLinkToExternalObj>this.className = GroupWise External Entity
[05/12/09 10:09:21.887]:GroupWise ST:GroupWise: validateLinkToExternalObj>objAssocKey = INTERNET.USERS{122}D04D4730-0DE4-0000-A0FD-F60098006300
[05/12/09 10:09:21.888]:GroupWise ST:GroupWise: validateLinkToExternalObj>newRecordType = 122
[05/12/09 10:09:21.888]:GroupWise ST:GroupWise: processAddEvent>objName = Test Contact8
[05/12/09 10:09:21.888]:GroupWise ST:GroupWise: processAddEvent>attrs = {50093=50093: Contact8, 50091=50091: Test, Record Type=Record Type: 106}
[05/12/09 10:09:21.889]:GroupWise ST:GroupWise: Creating object INTERNET.USERS.Test Contact8
[05/12/09 10:09:21.889]:GroupWise ST:GroupWise: processAddEvent>newRecordType = 106; externalFlag = true
[05/12/09 10:09:21.889]:GroupWise ST:GroupWise: processAddEvent>attrs = {50093=50093: Contact8, 50091=50091: Test, Record Type=Record Type: 106}
[05/12/09 10:09:22.002]:GroupWise ST:GroupWise: processAddEvent>objCtx.getGroupWiseID() = INTERNET.USERS.Test Contact8{106}D04D4730-0DE4-0000-A0FD-F60098006300
[05/12/09 10:09:22.003]:GroupWise ST:GroupWise: updateNDS>objCtx.getGroupWiseID() = INTERNET.USERS.Test Contact8{106}D04D4730-0DE4-0000-A0FD-F60098006300
[05/12/09 10:09:22.004]:GroupWise PT:GroupWise: GWpublicationShim.execute - processing event
[05/12/09 10:09:22.004]:GroupWise PT:




Success!!




The important snippet is here:


[05/12/09 10:09:21.883]:GroupWise ST:GroupWise:      classification = external
[05/12/09 10:09:21.883]:GroupWise ST:GroupWise: Add Event
[05/12/09 10:09:21.883]:GroupWise ST:GroupWise: class-name = GroupWise External Entity
[05/12/09 10:09:21.884]:GroupWise ST:GroupWise: validateParent>targetParentDN = null
[05/12/09 10:09:21.884]:GroupWise ST:GroupWise: validateParent>targetParentDho = INTERNET.USERS
[05/12/09 10:09:21.884]:GroupWise ST:GroupWise: validateParent>externalFlag = true
[05/12/09 10:09:21.884]:GroupWise ST:GroupWise: validateLinkToExternalObj>targetDN = null
[05/12/09 10:09:21.885]:GroupWise ST:GroupWise: validateLinkToExternalObj>targetDho = INTERNET.USERS
[05/12/09 10:09:21.885]:GroupWise ST:GroupWise: validateLinkToExternalObj>objAssocKey = null
[05/12/09 10:09:21.885]:GroupWise ST:GroupWise: validateLinkToExternalObj>parentFlag = true
[05/12/09 10:09:21.886]:GroupWise ST:GroupWise: validateLinkToExternalObj>forceParentExternal = true
[05/12/09 10:09:21.886]:GroupWise ST:GroupWise: getObjDN>Object DN = null
[05/12/09 10:09:21.887]:GroupWise ST:GroupWise: validateLinkToExternalObj>gwDN = null
[05/12/09 10:09:21.887]:GroupWise ST:GroupWise: validateLinkToExternalObj>this.className = GroupWise External Entity
[05/12/09 10:09:21.887]:GroupWise ST:GroupWise: validateLinkToExternalObj>objAssocKey = INTERNET.USERS{122}D04D4730-0DE4-0000-A0FD-F60098006300
[05/12/09 10:09:21.888]:GroupWise ST:GroupWise: validateLinkToExternalObj>newRecordType = 122
[05/12/09 10:09:21.888]:GroupWise ST:GroupWise: processAddEvent>objName = Test Contact8
[05/12/09 10:09:21.888]:GroupWise ST:GroupWise: processAddEvent>attrs = {50093=50093: Contact8, 50091=50091: Test, Record Type=Record Type: 106}
[05/12/09 10:09:21.889]:GroupWise ST:GroupWise: Creating object INTERNET.USERS.Test Contact8
[05/12/09 10:09:21.889]:GroupWise ST:GroupWise: processAddEvent>newRecordType = 106; externalFlag = true
[05/12/09 10:09:21.889]:GroupWise ST:GroupWise: processAddEvent>attrs = {50093=50093: Contact8, 50091=50091: Test, Record Type=Record Type: 106}
[05/12/09 10:09:22.002]:GroupWise ST:GroupWise: processAddEvent>objCtx.getGroupWiseID() = INTERNET.USERS.Test Contact8{106}D04D4730-0DE4-0000-A0FD-F60098006300
[05/12/09 10:09:22.003]:GroupWise ST:GroupWise: updateNDS>objCtx.getGroupWiseID() = INTERNET.USERS.Test Contact8{106}D04D4730-0DE4-0000-A0FD-F60098006300
[05/12/09 10:09:22.004]:GroupWise PT:GroupWise: GWpublicationShim.execute - processing event
[05/12/09 10:09:22.004]:GroupWise PT:



We can see that just before the Add event line, we have a new line that was not there before:



[05/12/09 10:09:21.883]:GroupWise ST:GroupWise:      classification = external


This is the key to all the magic that follows! Our setting of gw:classification="external" clearly took hold.



[05/12/09 10:09:21.884]:GroupWise ST:GroupWise:      validateParent>targetParentDho = INTERNET.USERS


This line shows us that it understood the 50035 (Domain) and 50062 (Post Office) settings we set to mean the external Post Office correctly.


[05/12/09 10:09:21.886]:GroupWise ST:GroupWise:     
validateLinkToExternalObj>forceParentExternal = true


Here is another hint that we are doing something with an External object.



The lesson to take out of this stuff, is that sometimes people write a lot of fluff in their articles and sometimes they really mean what they say, and the details are really important!



I hope anyone else running into this problem will be helped by this article.




Labels:

How To-Best Practice
Comment List
Related
Recommended