Load Balancing Exchange using Entitlements

0 Likes
over 6 years ago
Entitlements in NetIQ Identity Manager and I have a sort of love hate relationship. For the longest time, I preferred to use a custom attribute and have my driver implement it as appropriate.

Then I finally 'got it' with Entitlements and it started to make some kind of sense. As a consequence, I wrote up this series of articles on the topic.

Series: Talking about Entitlements

There are lots of fun and interesting things that the Entitlement tokens do in the IDM engine. Things you would not expect. Foremost among them, and worth reviewing is that when you use an Entitlement token, like the nouns for Entitlement, Removed Entitlement, Added Entitlement, you get a nodeset returned. If you use it as the nodeset a for each to loop over, then the current-node value is not what you would expect.

The Entitlement is stored in the attribute DirXML-EntitlementRef, and looks something like this.

      <modify-attr attr-name="DirXML-EntitlementRef">
<add-value>
<value timestamp="1422908960#4" type="structured">
<component name="nameSpace">1</component>
<component name="volume">\ACME-IDV-DEV\system\Driver Set\Active Directory Driver\ExchangeMailbox</component>
<component name="path.xml">
<ref>
<src>UA</src>
<id/>
<param>{"ID":"3E1234FFA3BEBE"}</param>
</ref>
</component>
</value>
</add-value>
</modify-attr>


In the case of more common tokens like looping over Operation Attribute (or Source Attribute, or Destination Attribute, you get the idea), you would get the contents of the <value> node as your current-node variable inside the loop. (It is worth noting that current-value only works in a Reformat Operation Attribute token, and current-op, the last of the set of "current variables" contains the entire event document for your manipulation).

In the case of the Entitlement tokens, you actually get the contents of the <param> node as current-node. In XPATH you could select it directly with an expression something like this:

modify-attr[@attr-name="DirXML-EntitlementRef"]/value/component[@name="path.xml"]/ref/param


I should note, I wrote that freehand and did not quite test it. There is some funny business around the path.xml that might get in the way. The point is, getting that in XPATH is a mouthful. Thus the built in tokens returning what we really want, the payload in the <param> node is great.

The old model of values in <param> initially was a single value, then came IDM 3.61 and the Compliance Management Platform and SAP Extensions which needed more than one parameter value, so the <param>ID=SomeValue|ID2=OtherValue</param> notation. With IDM 4 they switched over to JSON (JavaScript Object Notation) which would look more like <param>{"ID":"SomeValue","ID2":"OtherValue"}</param> format.

Regardless, the key to Entitlements was shown in the power of a Group Entitlement. This one object, defined how to query for values (all objects of class Group, returning the object name, the description, and the GUID (in DirXML-Association for that driver format). Then you specify the Group in your Entitlement granting action and the driver implements it. If you had 1 or 10,000 groups in your target system, this one object represents support for all of them.

So how do you select a value, especially when using a GUID for targeting it. GUIDs do not look good to humans. Thus came the ability to do a query to get all the values, and instead of showing only the GUID, now show the DN and the Description to help select, but store the GUID as the entitlement value.

With the JSON notation you can now have 2 parameters, so the value can be the ID with the GUID and ID2 with the DN which means the useful value, and the human readable value are both there. GUID of course is used, so a moved or renamed group is not lost.

However, along the same time came the notion of Resources (IDM 3.6 with User App 3.7 to be exact). There was an interesting article about what needed to be done to enable your driver to support Resources here: Convert Driver Entitlements to New RBPM 3.7 Resource Model

I decided to see just what was happening under the covers, and tell the WHY of the story, instead of the simple mechanics of adding support here: Converting Entitlements to Resources, more details

I think it is better to teach a man to fish, than to give him directions to assemble the fishing rod. (On that note, if you ever feel to urge to send me a gift in thanks, I happen to quite enjoy the many many variants on herring. Pickled, Schmaltz, various flavours, etc. And yes, someone did once mail me fish).

Knowing what the policies are doing, who uses it and why is critical.

With IDM 4.5 (and the tail end of 4.02) came the project formerly known as Jade, now known by the more marketing friendly name Permissions Collection and Reconciliation Service (PCRS). (I dunno, I kind of liked Jade in comparison. I just call it PCRS now. I heard one of the India dev's pronounce PCRS as a word and I had no idea what they were talking about until it became obvious from context and I started laughing when I figured it out).

PCRS does some very clever things that I am working on describing in a series of articles. But it makes the process I described of the creation of the entitlementConfiguration object very complex and crazy. (I do not mean it is bad, just it is very complex. I prefer more simple elegant solutions, but that is not always an option).

It also does some things I do not like, but that is me, always complaining.

One of the interesting things you will see if you dissect the policies involved, is that the various OTP and ITP policies seem to be goofing around with the <query> on the way out, and the resulting <instance> docs on the way back. There are lots of interesting examples if you look. Most drivers will respond to the UserAccount query with just the name of the system if there is no payload needed. They do that by catching the specific query in the OTP, converting it to the __driver_identification_class__ which every shim is supposed to respond to out of the box. This should return the driver shim name, version, and minimal license level to run it. This is what is actually used by the engine to determine if the licenses are good for this install.

I once tried to goof around with this query result, because I wanted to change one of the settings to support query-ex on a shim that did not otherwise allow it. (SOAP shim for Salesforce.com support). At that time it looked like the engine was preventing me from doing it. Which made sense, since then you could probably play games with the shim name and version which would be wrong.

Anyway, what I noticed was, we could tag the Exchange mailbox query that the shim does, by looking at the Entitlement definition, which looks like this:

<entitlement conflict-resolution="union" description="The Exchange Mailbox Entitlement grants or denies an Exchange mailbox for the user in Microsoft Exchange." display-name="Exchange Mailbox Entitlement">
<values multi-valued="true">
<query-app>
<query-xml>
<nds dtdversion="2.0">
<input>
<query class-name="msExchPrivateMDB" scope="subtree">
<search-class class-name="msExchPrivateMDB"/>
<read-attr attr-name="msExchOwningServer"/>
<read-attr attr-name="CN"/>
</query>
</input>
</nds>
</query-xml>
<result-set>
<display-name>
<token-attr attr-name="CN"/>
</display-name>
<description>
<token-attr attr-name="msExchOwningServer"/>
</description>
<ent-value>
<token-src-dn/>
</ent-value>
</result-set>
</query-app>
</values>
</entitlement>


I noticed that the query looks for a read-attr of msExchOwningServer, which is an attribute that is usually NOT in the IDM schema map for this driver, and likely of no interest otherwise. But it does look like it would uniquely identify this query. I could have just modified the Exchange entitlement XML so that the <query-xml> nodes copy of a sample <query> doc would have an <operation-data exchange="true"> node, but that would 'dirty' the base packages from NetIQ and I did not want too. The PCRS team had a clever idea, inside the <query> node they added an XML attribute event-id="ENTITLEMENT:Group" for the Group entitlement. (Alas, one of the complexity bits I did not like is that Designer has a bug that if you open the Entitlement and 'look' at it, it throws away the event-id attribute, even without saving. To work around this, there is a Startup policy that edits the Entitlement object on every startup. Meh, I would have preferred to get the Designer bug fixed than this approach. Also your Group entitlement object is always dirty. They should have just used the operation-data node approach I think.

Thus the solution I have is pretty simple. In the Output Transform, I test for a operation of query, a class name of msExchPrivateMDB, and a XPATH to make sure the read-attr for that attribute is present. Which inside the If XPATH expression is true says:

read-attr[@attr-name="msExchOwningServer"]


If all three conditions are met, set an operation property exchange-query to true. Then in the ITP I look for a query result (<instance> doc) with the operation property set.

Then I just use the Append XML attribute style tokens to build onto the end of the Query result one more node that looks like this:

    <instance src-dn="defer">
<attr attr-name="CN">
<value>Load Balancing Option</value>
</attr>
</instance>


What this means is that when User Application does its CODE MAP Refresh query, it injects an XDS query from the User App driver into the AD driver based on the query found in the entitlement objects definition. The results are the CN of the homeMDB, with the source DN being the value stored in the entitlement. (Interestingly not the objects AD GUID but rather the full DN. I dunno why that is.)

Well now when you go to User App to assign an Entitlement to a Resource, you see one extra option, whose name, instead of being EXCH-MDB-SERV2 is Load Balancing Option, and instead of a long DN path in the <param> node of the DirXML-EntitlementRef, you get simply something like below:

<nds dtdversion="4.0" ndsversion="8.x">
<source>
<product edition="Advanced" version="4.5.0.0">DirXML</product>
<contact>NetIQ Corporation</contact>
</source>
<input>
<modify cached-time="20150202202920.536Z" class-name="User" event-id="DevIDM#20150202202920#1#4:332f78bc-a36a-4be5-a9a6-bc782f336aa3" qualified-src-dn="dc=com\O=ACMENetworks\OU=Users\OU=Active\OU=Employees\CN=bobSmith" src-dn="\ACME-IDV-DEV\com\ACMENetworks\Users\Active\Employees\bobSmith" src-entry-id="75508" timestamp="1422908960#4">
<association state="associated">3131fee8c713684582d2b3ca82e42824</association>
<modify-attr attr-name="DirXML-EntitlementRef">
<add-value>
<value timestamp="1422908960#4" type="structured">
<component name="nameSpace">1</component>
<component name="volume">\ACME-IDV-DEV\system\Driver Set\Active Directory Driver\ExchangeMailbox</component>
<component name="path.xml">
<ref>
<src>UA</src>
<id/>
<param>{"ID":"defer"}</param>
</ref>
</component>
</value>
</add-value>
</modify-attr>
<modify-attr attr-name="homeMDB">
<add-value>
<value type="string">defer</value>
</add-value>
</modify-attr>
<operation-data>
<entitlement-impl id="" name="ExchangeMailbox" qualified-src-dn="dc=com\O=ACMENetworks\OU=Users\OU=Active\OU=Employees\CN=bobSmith" src="UA" src-dn="\ACME-IDV-DEV\com\ACMENetworks\Users\Active\Employees\bobSmith" src-entry-id="75508" state="1">{"ID":"defer"}</entitlement-impl>
</operation-data>
</modify>
</input>
</nds>


Where the key part is the line:
<param>{"ID":"defer"}</param>


Thus you have now added support for load balancing in Exchange, if you want it. No longer is it an either everybody is load balanced with defer, or everybody needs a homeMDB value specified somehow. Now you can use a resource for some users that is load balancing, and for others that is a specific MDB.

I liked how simple a solution this was, and it only took me an hour or two to get it completed, end to end.

I even built it into a package, which I will make available on the CIS package repository. (I work for a consulting firm, Computer Integrated Services LLC, as my day job. I just moonlight and write these articles for fun. Well mostly because I cannot remember everything I learn, so I write it down and search for it when I need it later. When my colleagues ask me a question about IDM, I usually can respond with a link to an article I wrote with the answer they need. Of course, they love it when I forget some detail and ask them, and they respond with a link to an article I wrote with the answer I needed.)

To use the Repository, go to Designer, Windows menu, select Preferences, expand NetIQ, then expand Package Manager, select Online Updates, and add a new Repository. Call it what you like, and set the URL to:

https://idmfolder.ciscony.com/cis-idm-repo/

Do a Check for Package Updates from the Help menu, restart and they will be available.

There are a bunch of interesting packages I make available there.

  • An add of for the Work Order driver that will do a better job on every polling cycle if you have lots of pending work orders. (Tested at a client with 24,000 pending WO's and it went from 10 minutes to 40 seconds a polling cycle. Faster if you turned off trace).
  • An Alternate Logging approach, based on Holger Dopp's truly excellent work on the SAP drivers. Turn off trace, use this instead and you get the performance boost, but also get to see much of what happened, or hopefully enough to get a hint of what went wrong. (Then turn trace on and reproduce to be sure).
  • A License clean up tool. Try to find all inactive users, disable them (or not, GCV controlled), remove any DirXML-Associatons, and critically clear the object class nrfIdentity (which is how the auditors screw you if you don't). It is not perfect, complete, but if you have a use case let me know and I will add support if I agree.
  • A Package I built for an article about Nodeset vs Strings.
  • A Multivalued Attribute cleaner, for when eDir has an attribute multivalued, and the target (mainly Active Directory) has it single valued. Save you those pesky errors.



Try them see if you like them.

Labels:

How To-Best Practice
Comment List
Anonymous
Parents Comment Children
Related Discussions
Recommended