Working with Cisco Unified Call Manager via IDM - Part 1

0 Likes
NetIQ Identity Manager ships with a number of drivers prebuilt to talk to specific systems, like Active Directory, Lotus Notes, SAP (UM, HR, and Portal), and many others. In addition, there are a number of API or protocol level drivers. For example the JDBC driver can talk to most any database which has a JDBC connector available. The Delimited Text driver (or Stephaan Van Cauwberge's free Generic File Driver) allows you to read text files, CSV, XML, or maybe even Excel files. The SOAP Driver lets you talk over HTTP using XML-RPC, SOAP, and certain flavours of REST.

In principle you could write your own driver as needed, to talk a native API, and many folk have in third party drivers.

But the protocol drivers are kind of neat since they allow you to connect to arbitrary systems that support their protocols. Specifically the SOAP driver is kind of interesting, as many new applications like to use web services to talk to them. (Heck even GroupWise 2014 is using REST (with XML) for the new administrative interface.)

The SOAP driver was initially proposed that you use an XSLT transform convert between XDS (NetIQ's XML Dialect that IDM uses in the engine, the usual <modify>, <add>, etc style events) to SOAP and then back from SOAP to XDS.

However the reality is, everyone implements a SOAP web service differently. Some have a single update API call, where you specify the object class, which is pretty easy to map to XDS. Others have a different API call for every single object class. Some have a few object classes, others have hundreds.

Thus your SOAP web service can be insanely difficult to deal with or trivial. Thus the XSLT can get really complicated and hard to manage.

I tried the XSLT approach and did not really like it. I had to do a SOAP driver to talk to Salesforce.com, which I detailed how I approached it in this series of articles:



In that series, I discussed how you might use DirXML Script to convert from SOAP to XDS and from XDS to SOAP, which I found more appealing than doing in XSLT. For one thing, the policy simulator is better for debugging the DirXML Script than the XSLT simulator.

My approach worked very nicely, and was easy to extend, where each API call had its own policy object to handle it which you could usually copy and paste and reuse with modifications to support the differences.

However my boss looked at that and said there had to be a better way to do this. He developed on a Workday.com driver, but rather than solve the Workday problem specifically and exclusively, he decided to work on the SOAP problem in general, with a specific implementation for Workday. He calls this approach LiQuiD SOAP, which we have since used for a number of other SOAP implementations. With the advent of Packages in Designer, we have been able to nicely package up the base LiQuiD SOAP and then add on packages for different web services.

If you happen to need a Workday, CUCM, or generic Web Service driver, please feel free to contact me, in my day job, I work at a consulting firm, and we would be glad to work with you.

Recently I had to work on a Cisco Unified Call Manager driver, and thought it would be worth talking about the strange complexities involved in this specific product.

When working with a web service the first thing you need to do is get the WSDL file (Web Services Description Language) and then load it into SOAP UI, (www.soapui.org) where it get parsed, and shown as individual function calls, with as much internal documentation as the vendor provides. The internal documentation here, is generally very weak, and the nodes in the SOAP calls rarely match the GUI values, since that would make life easy, so why do it that way? CUCM suffers from this excessively with names that make sense as fields, but rarely match what the GUI shows. Thus when you look in the user interface at a field, it is often pretty hard to figure out which SOAP element would represent it.

As I discussed in my series on building a SOAP driver, the first thing you want to handle is query events. This is because on almost every event, you do a query. Well maybe the first thing you want to do is figure out how to authenticate. Some SOAP systems use a specific call to get a token that is then used for the duration of the session. Others use HTTP Basic auth, which is what the CUCM SOAP interface uses, so no need to figure out logins. Basic Authentication uses an HTTP Header named Authorization: and has a value of the string Basic followed by the username:password base 64 encoded.

Often in SOAP UI if the Authorization tab does not work, I turn off the values there, and just add the header explicitly by hand.

The CUCM SOAP integration needs at least one more HTTP Header to work. For every call, you need a header explaining the name and version of your function call. For example, to query for a line object (which is really a Directory Number in the GUI, hmm, maybe we need a dictionary to translate SOAP to CUCM GUI) you need to specify a SOAP Action header of: "CUCM:DB ver=8.5 getLine". Because each new version of the CUCM product includes new features, you need to identify the version of the call you are using. (Sort of like the old days of Gradient DCE and versioned RPC calls!) Cisco maintains a compatibility grid somewhere in the docs (I lost the URL, sorry) that shows what functions are available with each version, and any changes between versions. Which is actually really nice, and I wish other vendors would do the same.

SOAP UI will set the SOAPAction header for you, based on the data in the WSDL, but in your implementation you will have to override drivers values with an <operation-data> node, containing an XML attribute named soap-action. This will tell the shim to add in the header for you.

If you look at the shim configuration on the driver properties tab in Designer, there are some headers it defines by default, and then 3 or 4 more you can define for the entire driver. However, for CUCM every event needs a different SOAPAction, but the good news is the shim lets you override it on each event.

Thus you need to add an operation property named soap-action, with the appropriate value. The node would end up looking like, at least this, though you probably will have more attributes in there.

<operation-data soap-action="CUCM:DB ver=8.5 listDeviceProfile">


You also will need a namespace declared for the same value like:

xmlns:ns="http://www.cisco.com/AXL/API/8.5"


Now if my advice is to first implement a Query, then the next CUCM specific issue arises. Every class has its own query function, and usually two. For example, the two classes I supported in my driver were Line and DeviceProfile objects. There is a getLine and listLine function, as well a pair of getDeviceProfile and listDeviceProfile functions.

This means you have to spend a lot of time handling all the many, many, many object classes. As a quick count, I came up with 159 get* functions, which I will assume have matching list* functions.

So what is the difference between getLine and listLine? This one took me a while to figure out, and you would think should have been clear in the docs, right? If it is, I never found it. Though there is a pretty good forum at Cisco's support web site that was very helpful in working through this, both in terms of finding old questions and getting answers to new ones.

It appears that listLine or any list* function, allows you use wildcards, to search for objects of the type. You can see this in the opening XML:

      <ns:listLine sequence="?">
<searchCriteria>
<!--Optional:-->
<pattern>?</pattern>
<!--Optional:-->
<description>?</description>
<!--Optional:-->
<routePartitionName>?</routePartitionName>
</searchCriteria>


Here you get a searchCriteria, which accepts wildcards, which happen to be % signs, not asterisks as you might expect.

Once you find your object, with a wildcard search, you can do a query for a single example of the object with getLine, which starts off a bit different:

      <ns:getLine sequence="?">
<!--You have a CHOICE of the next 2 items at this level-->
<pattern>?</pattern>
<!--Optional:-->
<routePartitionName uuid="?">?</routePartitionName>


Here you do not have any searchCriteria, rather you need to specify exact information to identify the object to be returned. You can always use the GUID, which is perfect for using as an association value. But otherwise, each object class has its own rules for uniquely identifying an object. In the example I show here, a Line object has two identifiers, a pattern, which is usually the name, and in the case of a Line (Directory Number in the GUI) a phone number style name. The second is the routePartitionName. It appears, you can have many instances of the same number, but they need to be assigned to a different Route Partition. Unsurprisingly, there is a getRouterPartition and listRoutePartition functions if you wanted to sync those objects into the Identity Vault. I did not find a need. In my specific case, all Device Profiles would get two Directory Numbers assigned to the first two buttons on the phone. The partition names were statically defined, PT Line 1 and PT Line 2, (Though amusingly, in the dev environment I worked in, it was PT Line then a space then a number. In Production however it was PT Line1 (no space), which made for fun troubleshooting. But I expect silliness out of people, so I assumed any literal string that they said would always be the same, would change without warning and used Global Configuration Variables (GCV) for them. This paid off nicely as the fix was only seconds.

The good news is, most of the time, you do not need to reference objects by their GUIDs and thus a name (based on a predictable pattern) suffices. But sometimes you do need the GUID.

This came up for me in two ways. First the case of a name sufficing. In the definition of a Line object there is a thing called a Calling Search Space (Known as a CSS, with, yes you guessed a getCss and listCss pair of functions). There about 10 different places you can specify a CSS, and I am not 100% sure what the exact meaning of this is, but who cares. We need it, we can implement it, the CUCM guru says it must be set, so we do it. Anyway, they had a CSS defined per location, but they were all named CSS XXX Local (where XXX is a three letter location code, stored on the User object) so it was easy to predict the string needed. Had I needed the GUID's from all of them, I would have had to implement the getCss, listCss functions, to import the objects into the directory, use the uuid returned (the GUID) as the association value, and then put a DN reference on the Line object to which Calling Search Space applies, or some other convoluted setup like that.

The second case has to do with Device Profiles. In that case, when you create a Device Profile, it is ok to name the associated Line objects (0 to however many line buttons your physical phone supports) by their pattern (number as you will recall) and their Route Partition Name. But when you need to change the values on a Line object, via a modify of the Device Profile (why not modify just the Line objects instead of Device Profile, with references to the Line objects? Long story, will get back to that later), I could not get it to work with just names, and resorted to using the GUIDs instead.

Anyway, that is a good start to the series, I have lots more fun things to talk about, like generic stuff here to help you understand their crazy model, but also some examples of errors I ran into with solutions, so stay tuned for more!















Labels:

How To-Best Practice
Comment List
Related
Recommended