Novell Identity Manager is a complex product. One of the factors that affects the level of complexity is that beyond the core engine functionality, you need to learn the vargaries of all the various connected systems.
With dozens of available drivers, and for several of those drivers connecting to several possible systems (LDAP, JDBC drivers for example) the possible error states are numerous, and to be honest, not really documented. Part of the problem is that many of the error messages really are self explanatory, as the error returned is pretty clear. Makes it kind of hard to get any motivation to document that kind of thing! But also because there are so many possible error states, it becomes almost an impossible task.
When I start with a new driver now, what I do is snap a quick copy of any error I run into, write a short note about what caused it, how I fixed it, and forget about it.
Then when I have some time I write it up as an article, that you are about to read.
For the JDBC driver, which can connect to many different databases (MS SQL 2000, 2005, 2008, Oracle v8, v9, v10, Postgress, MySQL, DB2, and possibly more) there are even more error codes than you can imagine. I have a series on the errors we saw while developing a driver to connect to Oracle 9.
You can read that series at:
I have enough error codes collected for part 5, I just have to get around to writing it!
In this article, I wanted to share some of the error codes I ran into with Active Directory. My hope is that by posting the text of the error messages (as I saw them in Dstrace, which if you are not familiar with, the definitive guide to reading Dstrace for Identity Manager is at: Capturing and Reading Novell Identity Manager Traces) someone else who runs into one of those specific errors, will be able to paste in the error message in Google, and find my article explaining what I did wrong, and how I fixed it.
I would love to see other people do the same thing for other drivers! So here is my challenge to you, dear reader. If you like my articles, then my fee for service is do the same thing I have been doing, collecting error codes! As you develop a new driver (even one you are very familair with, like the Active Directory driver here) and you see an error message in DSTrace, be sure to copy the message, describe the circumstances, and please post them for every one to benefit from! Believe me, if you run into one of this odd errors, Google it, and find an exact response, you will know exactly why it is worthwhile to do this sort of thing!
This time around, I was approaching an Active Directory driver from a slightly different perspective. This time, we had three domains to synchronize and wanted to only develop one driver, to share across all three. We had two different approaches possible, each with pros and cons. The first approach would be develop to one domain, then export to a configuration file. Import it as a second (and eventually a third) driver and just change the configuration information. That would probably work, but it has one major weakness. If you realize after you have built the second and third driver that there is a design flaw, or a minor change, then you have to remember to back and change the exact same thing in the other two drivers. This takes a strong level of self control to actually remember to document what you did, exactly, so you can reproduce it twice more.
The second approach, which we took, was to develop the driver once, but to make all the rules used in each part of the fishbone diagram, be linked from a Library object. (For more information on what each policy and rule does in that flow, you should read this truly excellent review of the topic by David Gersic ). Its a three parter, but well worth the read, and it makes a great reference! You will learn something from it! I know I did! A Guided Tour of Novell Identity Manager - Part 1,
A Guided Tour of Novell Identity Manager - Part 2, A Guided Tour of Novell Identity Manager - Part 3 )
We moved all the rules we were using into a Library object at the root of the driverset, and then when we export the configuration, it exports the links to the rules, and when we reimport it to build the second and third drivers, it uses the links instead of new copies of the rules.
This way, when we make a change in a single location, it affects all three drivers. Now the major downside is that you really need to test that the change you made works in all three domains. This is not always clear cut. However, we felt the trade off was worth it. Of course, if you decide to add a new policy object, or modify the linkage order, you would have to redo it in the other two drivers as well.
In order to manage the differences between the three drivers we end up with a number of Global Configuration Variables. These are great, and my favorite things! Use them, they are awesome!
Finally, on to the errors:
Invalid Credentails, Active directory side:
<nds dtdversion="3.5" ndsversion="8.x">
<status level="fatal" type="driver-general">
<message>unable to authenticate to Active Directory</message>
<ldap-err ldap-rc="49" ldap-rc-name="LDAP_INVALID_CREDENTIALS">
<client-err ldap-rc="49" ldap-rc-name="LDAP_INVALID_CREDENTIALS">Invalid Credentials</client-err>
<server-err>8009030C: LdapErr: DSID-0C0904D1, comment: AcceptSecurityContext error, data 52e, v1771</server-err>
<init-params event-id="write state">
This error is pretty clear and straightforward. We got an LDAP 49 error, with a sub code of 52e. Conviently, I had already written an article listing out all the sub codes for error 49, as I can never remember them all. Look at: Sub-Error Codes for LDAP Error 49
LDAP Error 49 is basically failure to authenticate successfully, and then subcode 52e means bad password, about the same as eDirectory's 669 error. You might see other codes like 525 which is the equivalent of eDirectory's 601 error, no such object. We have one of those later on in this article.
What happened here was I copied driver from one instance to another, forgot to set the password for the user in the new domain so of course got a bad password error. Passwords are stored encrypted in the driver object, much the same as named passwords are stored, (actually it is probably the other way around, that named passwords, an addition in Identity Manager 3.0, used the same existing mechanism for storing passwords as was already in use for the application, driver object, and remote passwords.
In this case, I needed to set the Application password in iManager on the Driver properties page.
672 Error, insufficient access, eDirectory side:
[04/03/09 15:34:17.631]:EMEA-AD PT:
<add class-name="Organizational Unit" dest-dn="Acme\Structure\corp\acme\emea\Germany" event-id="EMEA-AD##1206d78a891##0" src-dn="OU=Germany,DC=emea,DC=acme,DC=corp">
<add-attr attr-name="Object Class">
[04/03/09 15:34:17.633]:EMEA-AD PT:Filtering out notification-only attributes.
[04/03/09 15:34:17.633]:EMEA-AD PT:Pumping XDS to eDirectory.
[04/03/09 15:34:17.633]:EMEA-AD PT:Performing operation add for Acme\Structure\corp\acme\emea\Germany.
[04/03/09 15:34:17.634]:EMEA-AD PT:Adding entry Acme\Structure\corp\acme\emea\Germany.
[04/03/09 15:34:17.634]:EMEA-AD PT:Creating RDN Germany in context Acme\Structure\corp\acme\emea.
[04/03/09 15:34:17.642]:EMEA-AD PT:
DirXML Log Event -------------------
Object: OU=Germany,DC=emea,DC=acme,DC=corp (Acme\Structure\corp\acme\emea\Germany)
Message: Code(-9010) An exception occurred: novell.jclient.JCException: createEntry -672 ERR_NO_ACCESS
This error occured once I got the driver up and running. Then the first thing I wanted to test was to make an object in Active Directory (an Organizational Unit in this case) and see if it would synchronize to eDirectory.
You can see that all looks good, but as it gets sent to eDirectory to write, we get a 672 error. 672 errors have about a dozen possible causes, and often the simplest is the explanation, insufficient access. In this case, I forgot to do Security Equivalences when I imported the driver! No access because the driver object has no rights to write to eDirectory.
You can fix this in iManager or Designer, via the Security Equals options. In iManager it is on the Driver properties page, and there is a Security Equals tab. In Designer, because this is a live operation, as opposed to an offline operation (you have to make changes in eDirectory for it to have any meaning, and it is not something that can be deployed) it is a separate menu option, right click the driver connection line, select Live, and at the bottom you can Manager Driver Security.
I personally am lazy and instead go straight to the object in ConsoleOne, right click to get the Properties, then on the Other tab, I add an attribute Security Equals and pick the object we use that has enough rights. During devlopment I usually use an Admin object because I am lazy. Once we roll out to production, I make an object, exclude it from synchronization (which sets a DirXML-Association value of 0) and give it sufficient rights, only to the desired containers.
This error was all about not having enough rights to write to eDirectory. There is another version of the same basic error, where the driver cannot read the attribute it wants. This one is less obvious, so often it is easier to spot the 672 error in trace first.
10:50:48 DBA19BA0 Drvrs: Active Directory ST:Driver object has insufficient rights to read \ACME-LAB-IDV\Acme\Users\Testing#DirXML-ADContext.
You can see that it was trying to read DirXML-ADContent on a user named Testing, and failed with insufficient rights. Same solution as above fixes this, set Security Equals on the driver object.
LDAP Referral error:
<nds dtdversion="1.1" ndsversion="8.7">
<product asn1id="" build="20080229_143300" instance="\ACME-LAB-IDV\Acme\Drivers\IDM\Active Directory" version="3.5.3">AD</product>
<status event-id="0" level="error" type="driver-general">
<message>Error getting next page of search results</message>
<ldap-err ldap-rc="10" ldap-rc-name="LDAP_REFERRAL">
<server-err>0000202B: RefErr: DSID-03100768, data 0, 1 access points ref 1: 'acme.com'</server-err>
This error should not normally happen, which makes it even more fun, since it did! When I was first starting in on this project, there were a number of people involved, and I did not fully understand what every server was doing. In particular, I did not know that the names of the Active Directory domain I was connecting too was different than I was expecting. Thus I was looking for objects to match, in the wrong base DN in Active Directory. I thought it was acme.com and in reality the domain was named acme.corp. Thus on the query, it would fail, with an LDAP referral error, since it could not figure out where to refer my query to complete it.
As you can see, this should never really happen in the real world, since who makes typos after all? Good to know what it would look like if you did though!
Operation Vetoed by Create Policy (No UP):
19:00:00 DBA19BA0 Drvrs: Active Directory ST:Applying policy: [Acme] sub-AD-Creation.
19:27:54 DBA19BA0 Drvrs: Active Directory ST: Applying to add #1.
19:00:00 DBA19BA0 Drvrs: Active Directory ST: Evaluating selection criteria for rule 'Veto if nspmDistributionPassword is not available'.
19:00:00 DBA19BA0 Drvrs: Active Directory ST: (if-class-name equal "User") = TRUE.
19:00:02 DBA19BA0 Drvrs: Active Directory ST: (if-global-variable 'enable-password-subscribe' equal "true") = TRUE.
19:00:00 DBA19BA0 Drvrs: Active Directory ST: Rule selected.
19:00:31 DBA19BA0 Drvrs: Active Directory ST: Applying rule 'Veto if nspmDistributionPassword is not available'.
19:01:40 DBA19BA0 Drvrs: Active Directory ST: Action: do-veto-if-op-attr-not-available("nspmDistributionPassword").
19:00:00 DBA19BA0 Drvrs: Active Directory ST:Policy returned:
19:00:00 DBA19BA0 Drvrs: Active Directory ST:
<nds dtdversion="3.5" ndsversion="8.x">
19:07:09 DBA19BA0 Drvrs: Active Directory ST:Processing returned document.
19:00:00 DBA19BA0 Drvrs: Active Directory ST:Processing operation <status> for .
19:00:01 DBA19BA0 Drvrs: Active Directory ST:
DirXML Log Event -------------------
Driver: \ACME-LAB-IDV\Acme\Drivers\IDM\Active Directory
Message: Code(-8017) Operation vetoed by object creation policy.
Error code 8017 is not really an error in the usual sense, as you can see the Status level is actually just Warning. Usually these cases are because the object being processed is missing some attribute. Actually it happens when ever a Veto occurs in the Create or Placement policies. There are lots of cases where this is normal.
On the Publisher channel, this is very common because the User in Active Directory is missing a mandatory attribute that eDirectory schema requires. Usually Surname in the case of User objects. That is because eDirectory will not let you make a user without specifying a Surname value. It is built into base schema, and while technically you might be able to change base schema with a properly constructed LDIF file, it is probably inadvisable.
An amusing case where this becomes an issue is with some Indonesian folk who apparently only have first names, and do not have Surnames at all. When you need to create User objects for them, you need to make a decision of what you will put in Surname, usually I just throw my hands in the air and just call their first name their last name. I am not sure what better way there is to handle this. I have seen putting the first letter of their first name in as their Surname but I am not sure that is better.
On the Subscriber channel, sending events into Active Directory there are two mandatory attributes (well one is mandated by Active Directory (Full Name), the other because it makes sense (a password)). Active Directory allows users to be created with a Given Name or Surname, but needs to have a value for Full Name. The default driver configuration requires that there be a nspmDistributionPassword as well. The reason for this one is that Active Directory will not let you make a user that is active without a password, unless you set the bit to allow that. In the usual case, if you create a user without a password they are disabled. Which is probably not what you want.
This one had me scratching my head, since I knew I had set a password on the User. But again as I learned on this project, I was walking into a half configured world, so I decided to see if Universal Password was even enabled in this tree.
Lo and behold there was no Password Policy defined nor assigned to any users in the tree. This was easy enough to fix. In iManager, in the Passwords section, I was able to define a Password Policy that matched the production policy, and assign it to the entire tree. Once that was done, I had to set the password again, to populate Universal Password. (I suppose I could have done an LDAP bind which under eDirectory 8.8 at least, should see that the policy says to use Universal Passwords, and although I authenticated with the value from the RSA key pair (aka NDS password) I should set it in Universal Password as well. Client32 does this as well on logins, if you have NMAS installed and a reasonably new version.
Depending on your application being connected too, you may have other requirements on an object before it can be sent to the connected system, or sent back to eDirectory. An example might be a flag, like acmeAllowADAccount set to true. This would allow you to control which accounts get sent to the connected system, as they would require a flag attribute (that you make up, or reuse some existing attribute, perhaps group membership) before being allowed past the Create rule.
Hopefully this beginning has whetted your appetite for more error codes, so stay tuned for part two of this series, where we have lots more error codes coming. We shall have to see how many more I can track down to write about.
As always, I encourage everyone to start doing this themselves. As you start working on a driver be sure to copy and paste any errors you run into, so that everyone can share from what you learned along the way.