Novell Identity Manager introduced the concept of Entitlements several versions back. In fact, I am not sure when they got added, I imagine around the Identity Manager 3 or 3.5 time frame.
Entitlements bring with them several bits and pieces scattered about the product. There is the Entitlement itself, the granting agent, and then how it is actually used.
First off there is the Entitlement itself. This is contained in a multi valued attribute, DirXML-EntitlementRef that is part of the DirXML-EntitlementRecipient auxiliary object class. It is Path syntax, one of my favorite syntax types, which means it has a 32 bit integer (nameSpace component), a DN reference (ironically actually also a 32 bit integer under the covers, but displays as a DNm the volume component) and a string (the path component, which interestingly enough in this case is actually named path.xml instead of just path and has some interesting properties).
The nameSpace component is used to indicate the state of the entitlement, just like in a DirXML-Association. In this case 0 is revoked, and 1 is granted. A bit of a waste of a 32 bit integer to really store a boolean, but whatcha gonna do? The volume component, the DN is meant to be the distinguished name of the Entitlement object. The Entitlement object stores the configuration information and is used as a way to reference it. That sounds silly, but you need to name something to talk about it, right? Well an object requires a name and thus if nothing else, now we can talk about it. The path.xml component stores the payload of the Entitlement as a string, which is formatted as XML.
The Entitlement object itself is a DirXML-Entitlement object with only three attributes of interest. CN for naming (which is of course mandatory as eDirectory requires a naming attribute on every object, else how do you discuss it?), XMLData, a Stream syntax attribute, which is a blob to store the raw XML information that is used to define the entitlement, and DirXML-SPCachedExternalQuery which is a Stream syntax as well. I suspect this may be a bit of legacy from the days when Entitlements were initial conceived to be the results of an LDAP dynamic query, and I wonder if perhaps they intended to cache some of that query in this attribute for performance reasons. Looking at live systems, I do not understand what this attribute is used for in this case, but nonetheless it is the XMLData attribute that is usually key.
The XML stored for a simple Group Entitlement that uses values from the application, the XML looks something like this:
<entitlement conflict-resolution="union" description="The Group Entitlement grants or denies membership in a group in Active Directory. The group must be associated with a group in the Identity Vault. When revoked, the user is removed from the group. The group membership entitlement is not enforced on the publisher channel: If a user is added to a controlled group in Active Directory by some external tool, the user is not removed by the driver. Further, if the entitlement is removed from the user object instead of being simply revoked, the driver takes no action." display-name="Group Membership Entitlement" name="Group"> <values> <query-app> <query-xml> <nds dtd-version="2.0"> <input> <query class-name="Group" scope="subtree"> <search-class class-name="Group"/> <read-attr attr-name="Description"/> </query> </input> </nds> </query-xml> <result-set> <display-name> <token-src-dn/> </display-name> <description> <token-attr attr-name="Description"/> </description> <ent-value> <token-association/> </ent-value> </result-set> </query-app> </values> </entitlement>
For a simple Entitlement where the Administrator has defined multiple values, it might look something like this:
<entitlement conflict-resolution="union" description="Simple preset valued entitlment" display-name="Group Membership Entitlement"> <values multi-valued="true"> <value>Value1</value> <value>Value2</value> </values> </entitlement>
So what does an Entitlement look like? Well there are two ways it matters if you are working low level. First as an add or modify event and second as the response to a query event. In fact, I keep these two sample docs handy for working in Simulator, since I need to provide input documents to start the process, and query result documents when asked to provide them.
You can read more about using Simulator in this article I wrote on the topic: Using Simulator in Designer
Here is an <add> event document, that includes the DirXML-EntitlementRef attribute. One of the cool things about Simulator is that if you decide you would prefer a modify event to work with, you actually can select Add in the drop down at the top, paste in the Add event provided into the XML Source tab, switch back, and from the drop down, if you switch from Add to Modify, or even Instance, it will convert the document for you, which is actually a really nice feature. Especially if you are looking for some way to make a complicated <add> event sample you might have, into an <instance> doc, for other reasons.
<nds dtdversion="3.5" ndsversion="8.x"> <source> <product version="126.96.36.19904">DirXML</product> <contact>Novell, Inc.</contact> </source> <input> <add cached-time="20110221221739.710Z" class-name="User" src-dn="\ACME-TEST-05\edu\acme\People\cs102150" src-entry-id="813253" timestamp="1298326659#1"> <add-attr attr-name="DirXML-EntitlementRef"> <value timestamp="1298326653#2" type="structured"> <component name="nameSpace">1</component> <component name="volume">\ACME-TEST-05\services\IDM\DriverSet\ADDriver\EntitleTest1</component> <component name="path.xml"> <ref> <src>RBE</src> <id>services\IDM\DriverSet\Entitlement Policies\RBE-RoleTest1</id> <param>SponsoredAffiliate</param> </ref> </component> </value> </add-attr> <add-attr attr-name="Surname"> <value timestamp="1298326652#26" type="string">Testing</value> </add-attr> </add> </input> </nds>
If the driver needs to query for the Entitlements of a user, for example if you used the token if entitlement is available, it will look at the event document, and if it is not there, query back to the source for the DirXML-EntitlementRef values. Here is the result of such a query.
<nds dtdversion="3.5" ndsversion="8.x"> <source> <product version="188.8.131.5204">DirXML</product> <contact>Novell, Inc.</contact> </source> <output> <instance cached-time="20110221221739.710Z" class-name="User" src-entry-id="813253" timestamp="1298326659#1"> <attr attr-name="DirXML-EntitlementRef"> <value timestamp="1298326653#2" type="structured"> <component name="nameSpace">1</component> <component name="volume">\ACME-TEST-05\services\IDM\DriverSet\ADDriver\EntitleTest1</component> <component name="path.xml"> <ref> <src>RBE</src> <id>services\IDM\DriverSet\Entitlement Policies\RBE-RoleTest1</id> <param>SponsoredAffiliate</param> </ref> </component> </value> </attr> </instance> </output> </nds>
Now you will notice that the path.xml component has the following XML in it.
<component name="path.xml"> <ref> <src>RBE</src> <id>services\IDM\DriverSet\Entitlement Policies\RBE-RoleTest1</id> <param>SponsoredAffiliate</param> </ref> </component>
What is neat, and alas, I lost the error message in an unsaved text editor when my machine rebooted, is if you send an Entitlement through by hand, (I tried making it in iManager via the General tab) and it is not valid XML, then the driver will actually throw an error explaining that the path.xml component did not contain valid XML.
This demonstrates again that Console One is still a better arbitrary attribute editor than iManager. Interestingly enough, and I am not sure why, but for Path syntax attributes, the iManager UI does not let you control the data well enough. This is two fold. First the nameSpace attribute is not available to provide values for. Thus you only get two choices when editing such an attribute, the Volume DN and the path string.
Second, being a web application entering XML is always tricky, since it needs to be properly escaped and parsed, and just typing some simple XML into path string field is thrown away, and thus you get the error I lost my copy of, for non-valid XML value in the path.xml component.
Console One on the other hand will let you do what you need to do quite handily. Or you can use LDAP. The LDAP representation for reasons I do not understand is swapped around from the internal representations. That is, when you see an event come through IDM for a Path syntax attribute, the order is always nameSpace, volume, then path. In the LDAP world, it is displayed (and thus written as well) as volume a # sign, nameSpace, a # sign, and then the path component.
Now the payload for the path.xml component varies. This is because there are actually three different entitlement granting agents available.
- Roles Based Entitlements (RBE) driver,
- Roles and Resources driver (part of RBPM 3.7)
- Workflow (via Grant Entitlement or Role activity)
The Roles Based Entitlement driver was the first approach to this issue and ran into some salability issues You use the iManager snapin to manage the Entitlements Policies objects, which reside as a child of the Driver Set object. There is an annoying thing, that the iManager snapin REALLY wants to be the only thing editing the attribute, so when you use it, and stop the RBE driver, it actually writes a lock flag to the driver, which means the IDM plugins, Designer, nor dxcmd can restart the driver. The only solution is to finish editing it in iManager, and select Start driver from the RBE snapin. As I understand it, you look for the DirXML-SharedProfileSet object, which is a sibling of the driver (child of the driver set), called Entitlement Policies, and look for an attribute DirXML-SPUIEditorLock and that is the attribute causing you the problems. The RBE driver looks at that object and will fail to start if it is available
Now part of this has to do with the way the query filter is defined. It looks like you enter it stored as a simple text string representing an LDAP query that defines a dynamic group. Like (&(objectClass=User)(acmeEnableServiceA=true)) for users with the acmeEnableServiceA flag set to true. However, I am told the data is actually optimized and stored in some binary format to make it more efficient. Thus editing it by hand would be a very bad thing indeed, unless you fully understood the underlying data structure.
Thus the driver would look for basically dynamic group memberships, and when any of those would change, would revoke or grant the specified entitlement as mentioned.
I recently was at a client with over a million users, over twenty such entitlement policies, and it did still work, but it was clear they had scaled probably to an upper limit. Additionally, there is a ‘feature’ in Designer that really causes pain in this case. Many of those million users have several entitlements, thus the entire dynamic group membership list is in the millions of objects. Well every time Designer touches the Entitlements Policies container, it decides to evaluate the group memberships. Thus on an import of a driver set, you could see pauses up to two hours long depending on connectivity as it retrieved millions of group members, to then discard them. This meant a huge delay in importing and even some compare operations. But also it meant that Java’s garbage collection needed to go get rid of millions of orphaned memory fragments, which caused additional delays.
There is a bug reported for Designer 4, so hopefully we will get a patch in the near future, but also, you can just define an Admin user for use in Designer that just does not have rights to that container and the issue goes away. (Of course it technically is not a bug, its just when returning millions of values, it can take a long time, for which the data retrieved is kind of pointless).
However, if you block via an IRF (Inherited Rights Filter, a ACL that blocks inheritance of rights in eDirectory. Do be sure to explicitly grant the Admin user or three rights to these containers so as not to block them out of management for them.) the rights to the Entitlements Policies container. It may just be easier for the short term to just create an account and grant it rights to each driver explicitly and that works as well.
Once you do that Designer imports lickety split and actually gets the [Public] rights to see the name of the policies, just not their content, which is probably fine, as I still manage these in iManager most of the time.
One of the problems with the RBE driver approach is that there is no way to share the load for monitoring all these entitlement policies across multiple drivers, so you can only have a single such driver. This of course brings up scaling limits right away. When there are many thousands of recipients of such a policy, performance drops as well.
The driver is watching for changes in its filter defined list of entitled users, to go grant or revoke the DirXML-EntitlementRef attribute. To make this lightly complex, there is a difference between removing the entitlement and revoking it. Revoking it changes the nameSpace component to 0 from 1. Removing it would be a delete of the attribute value entirely.
What is interesting is the Condition test, if Entitlement, when used with an ‘available’ test will look at the operation document and see if the mentioned entitlement is being added or revoked. But if it does not see it, like the Attribute token, it will look back at the source, and ask for the DirXML-EntitlementRef attribute set of values, and then determine from there, if the entitlement specified is available.
What is also interesting, is that if there is more than one instance of the same entitlement on the object (Ya I know, should not happen, however if you ‘simulate’ the driver by hand via LDIF, this is the sort of thing that happens in testing) it will look at them in order they are returned. Thus I had a User with two instances of the Entitlement granted (State of 1) and one instance of it revoked (State of 0) and the end result was to consider this a revoked entitlement. There is some interesting trace events when using entitlements, that get added to the operation document in the operation data area, that help hint at what might be going on in the background.
There is probably more to say on this topic, but lets move on to the next part of this series, and discuss the other two entitlement granting agents, the RBPM Roles and Services driver, and the Workflow activity. Stay tuned for the next part in this scintillating series about a mostly boring topic. Hope you enjoy!