Walking through the IDM 4 Google Apps Driver – Part 2

geoffc

By: geoffc

February 29, 2012 12:49 pm

Reads: 346

Comments:0

Rating:5.0

This entry is part 2 of 11 in the series Walking through the IDM 4 Google Apps Driver

With the release of NetIQ Identity Manager 4.0 Support Pack 1 (aka IDM 4.01) some bug fixes, and a few new features were added.

Specifically three partner provided drivers were included, an RSA Driver, a Blackboard driver, and a Google Apps driver.

I discussed some of the new features and bugs fixed in IDM 4.01 in this series of articles:

I have been working on a series of articles walking through driver configurations, policy by policy to try and understand what the driver is doing, under the covers.

You can see more of these walk throughs on a Wiki page I maintain to keep them all together: Detailed driver walk through collection.

For this series of articles I would like to start looking at the Google Apps driver in IDM 4.01, that is provided by Consensus Consulting.

In the first article in the series I worked my way through the Subscriber Event transform and half way through the Matching Policy set.

In this article lets finish the Matching Policy set and keep going from there.

There are four policy objects in the policy set.

  • NOVLGGLECNTC-MatchingRule
  • NOVLGGLEGRPS-MatchingRule
  • NOVLGGLEORGU-MatchingRule
  • NOVLGGLEUSER-sub-mp_MatchingRule

The first two were covered in the previous article, now on to the second half of the policy set.

NOVLGGLEORGU-MatchingRule

This is a matching rule for Organization objects. In this case, same as groups, break if not Organizational Unit object class, and then a pair of GCV’s are considered:

  • gcv.NOVLGGLEORGU.googlePlacementOption
  • gcv.NOVLGGLEORGU.AllowOrgUnitsSyncToGoogle

In this case the first one is likely to control whether or not Organization Units are being placed in Google, since if you have not specified a method then odds are good it won’t work to place it. The second GCV controls whether they are allowed to sync at all.

Next up is a veto for not being in the correct subtree, that is, under the Users container. Probably this is not going to suffice for most and you will want to tweak this one so it looks where ever you really want your orgs to reside.

Finally it matches by the DN, but by using a cool function of the find matching token, the Unmatched Source DN functionality.

This is pretty neat how it works. It is managed in conjunction with the if Source DN in subtree, which when used, sets an unmatched-src-dn operation property I believe (or I might be remembering the Active Directory driver wrong, and it might set it explicitly, regardless) that can be used in the next following Find Matching Object token.

So if I say, if source DN is subtree idm\users and the Org unit being synced is idm\users\Students\Engineering\Fellows then yes, it is in the idm\users subtree, and the unmatched source DN part is every thing after the idm\users, in other words Students\Engineering\Fellows.

This is one of those things that is not clearly explained in the docs, to my mind but you can quickly derive and understand it from looking at most any driver configuration.

NOVLGGLEUSER-sub=etp_MatchingRule

Now on to users. As usual, break if not this class. Then check the Source DN, if it’s in the correct subtree using a GCV idv.dit.data.users

Next up is check entitlements. This uses two GCV’s:

  • gcv.NOVLGGLEUSER.RequireUserAccountEntitlement
  • gcv.NOVLGGLEUSER.MatchUserWithoutAccountEntitlement

to control whether the user can be created without an entitlement, or match without an entitlement. As in the case of Groups, although you may require an Entitlement to get a new account, often the horses are well out of the barn and even though you want to use entitlements, you need to match existing users, even if they do not have the entitlement since it is much better to control them going forward than to leave them stranded. By using this pair of GCVs which is more subtle than the usual approach of a single check that would block creates and matching users without entitlements, you have the ability to make that decision. Should really suggest that NetIQ update their base Entitlement packages to support this approach as well. It is quite clever, and a very nice subtle enhancement.

Interestingly enough, because the Entitlement processing used in most drivers is broken out into a Package per driver you could create your own, based on NetIQ’s default Package and then update it to add this enhancement. So could Consensus which would be kind of a neat idea.

The major downside is that if NetIQ offers an updated Entitlements Package in the future, you would need to look at the new Package, compare it to the previous version to understand the changes made, and then update your Package with the change. If it mattered. The problem with this is that the Readme for Packages often does not (ok, lets be real. NEVER) offer enough detail to avoid having to look in depth at it.

Now it turns out it is pretty easy to do if you think about it. Deploy a V1.0.1 package to an existing driver. I.e. What you have running in the lab. Then you would upgrade to the new Package build in Designer, which is as simple as selecting Upgrade on the Package tab of the Driver properties. Then when you do a Compare, Designer will do all the hard work for you and show a summary of all the changes, in the manner you are most used to seeing it. Then you will know what they changed and can easily figure it out.

The problem is that the fidelity of the Package model is at the Policy object level and there is no easy way to make minor tweaks to a Package in your own add on Package, you have to replace the entire Policy object. However it is so much better than the previous configuration file approach that I am on the whole happier.

Anyway if those two GCV’s are true, then you must have the GCV, so if the entitlement NOVLGGLEUSER-Account is NOT available then you veto the event.

Next up is a rule, Set Email Address Variable to Match Against, which is kind of interesting.

Entitlements can have a value, and in the case of the Google Apps driver, the value of the Entitlement can be the proposed email address for the user. Thus this rule has to handle a number of cases. If there is an entitlement, get the proposed email address. If not, get the Internet EMail Address attribute value, and if there is no such value, then calculate it as the Source Name followed by @ the Google Apps domain specified in the configuration.

So first up is a test if the entitlement NOVLGGLEUSER-Account is available, in which case it uses an ECMA function call of:
es:getEntParamField($current-node,’ID’)

This ECMA function comes from the NOVLIBAJC-JS ECMA library object. The AJC is the Advanced Java Class that Novell Consulting wrote in Java years ago to make their consultant’s lives easier. There were a bunch of functions in Java that did stuff like time conversion, and many other things much easier than could be done in Policy at the time, since tokens to make those things easier came in later versions.

With the release of ECMA Script support in Identity Manager 3.5 they had one of the core engine developers port all the Java functionality into an ECMA library. This is because an ECMA object can be contained or imported into a configuration trivially whereas a Java library needs to be copied into the file system of the engine server which is one extra step.

The ECMA function, getEntParamField() is actually four functions that are part of the lib-AJC library. If you use Packages in IDM 4 then you will have this, as it is part of common content that most drivers require. If you are running IDM 3.6.1 I suspect you will have an older copy of this ECMA Library object and may not have these four functions. However if you do not, then the existing function should be there, only supporting the legacy formatting. Which makes it nicely backwards compatible. Very classy.

getEntParamField(param, field)
getEntParamFieldBackwardsCompatible(param, idm4field, legacyfield)
getIDM4EntParamField(jsonstr, field)
getParamValue(paramString, paramName)

Which are defined below:

/** 
 * Get named field form an entitlement parameter string
 * The function tries to determine the parameter format automatically and parse the parameter accordingly
 *
 * @param param      parameter string ( e.g. '{"ID":"b53b65bb0b921548b8830cc698666dc2","ID2":"CN=PamelaGroup,CN=Users,DC=carpathia,DC=qalab,DC=com"}' or 'AG=Group1|LSNAME=S7ECLNT315|FROM=|TO=')
 * @param field      field name
 * @return value     field value
 */
function getEntParamField(param, field)
{
	return getEntParamFieldBackwardsCompatible(param, field, field);
}

/** 
 * Get named field form an entitlement parameter string.
 * The function tries to determine the parameter format automatically and parse the parameter accordingly. 
 * If the field names have changed from the legacy format to the idm4 format, this method allows both field names to be specified.
 *
 * @param param        parameter string ( e.g. '{"ID":"b53b65bb0b921548b8830cc698666dc2","ID2":"CN=PamelaGroup,CN=Users,DC=carpathia,DC=qalab,DC=com"}' or 'AG=Group1|LSNAME=S7ECLNT315|FROM=|TO=')
 * @param idm4field    idm4 format field name
 * @param legacyfield  legacy format field name
 * @return value       field value
 */
function getEntParamFieldBackwardsCompatible(param, idm4field, legacyfield)
{
	param = String((new JString(param)).trim());
	if (param.charAt(0)=='{' && param.charAt(param.length-1)=='}')
	{
		try {
			return getIDM4EntParamField(param, idm4field);
		}
		catch (e) {
			return getParamValue(param, legacyfield);
		}
	}
	else {
		return getParamValue(param, legacyfield);
	}
}

/** 
 * Get named field form a JSON-formatted IDM4 entitlement parameter string
 *
 * @param jsonstr    JSON string ( e.g. {"ID":"b53b65bb0b921548b8830cc698666dc2","ID2":"CN=PamelaGroup,CN=Users,DC=carpathia,DC=qalab,DC=com"} )
 * @param field      field name
 * @return value     field value
 */
function getIDM4EntParamField(jsonstr, field)
{
	var jsonobj = eval('(' + jsonstr + ')');
	return eval("jsonobj." + field);
}

/** 
 * Get named parameter value form a pipe-delimited (|) string
 *
 * @param paramString   parameter string string ( e.g. AG=Group1|LSNAME=S7ECLNT315|FROM=|TO= )
 * @param paramName     parameter name
 * @return value     	parameter value
 */
function getParamValue(paramString, paramName)
{
	try {
		var pairs = String(paramString).split('|');
		for (i in pairs) {
			pair = pairs[i].split('=');
   			if (pair[0].equals(paramName)) {
				return pair[1];
			}
		}
	} catch (e) {
		return String(paramString);
	}
	return paramString;
}

If I understand these correctly, the old function call, getEntParamField() has been replaced since there are now at least two different methods of storing the parameter information in the entitlements path.xml component, which I like to call the payload.

Previously, it looks like the values inside the payload part of the DirXML-EntitlementRef were pipe (|) separated. That is, if there was more than one value (imagine the SAP UM Fan out driver, where you might wish to entitle a user to access to many systems). You might apply one entitlement per system, but it also supports one entitlement with 1 or more values, so that the entitlement could handle multiple values.

There also is a new format, which I am not sure when it was introduced. I am looking at an IDM 4.0 set of rules, but I know (not from reading the IDM 4.01 docs since after scouring them, I have yet to find this directly mentioned, instead I found out in one of the Novell support forums) that the entitlement format changed in IDM 4.01 to allow multiple values. I am still trying to find out what this actually means. Regardless, I infer that at least one aspect of it, is handled by this ECMA function.

Thus when you call getEntParamField() to keep older policies working, it just chains and calls getEntParamFieldBackwardsCompatible which then tries two different approached. If the first and last character of the value passed in are { and } (open and close curly braces) then it will use the JSON version of parsing this data. That is, it will first wrap it in open and close round brackets, and then takes that value and appends a .fieldname and executes (eval()’s) that statement to get the field name out of the JSON

In the other case, it uses the older approach in getParamValue() of splitting it by the pipe sign. Then when it finds the parameter you passed in, it splits it on the equal sign, and returns the value from after the equal sign.

This way both approaches are supported, using the same ECMA function call in the policy, which by updating the underlying ECMA function definition requires no changes for the upgraded system. That is a nice approach to backwards compatibility.

Anyway, once it has pulled out the ID parameter from the <path.xml> node which holds the payload for the entitlement, it will then add a value to the member attribute of the group referenced (The group is referenced by its association value, which is what is stored in the payload in the ID field) by the entitlement.

Thus this one initial ECMA call will handle everything needed quite nicely and return the proposed email address.

If there is no entitlement, then grab the source attribute Internet EMail Address for the desired email address. And failing that build a proposed email address using the Source Name of the object and then the GCV holding the proposed Google Apps domain.

This is alas a simple implementation, since I recently reviewed the Consensus Student Interoperability Framework (SIF) driver in a similar series and they have a lovely complex model for naming, which allows huge flexibility based on incoming data. It was very clever and elegant. Alas they did not provide that level in this driver. Probably not a big deal, but only in comparison does it look a bit weak.

To read about the SIF driver walk through you can check out this article series:

In any of the three cases, the value is stored in a single variable to make it usable later in the policies.

In Google Apps, the email address is basically the only unique identifier, therefore the Match is done on based on email address variable. In this case, CN is mapped to UserName in Google.

If that does not match yet, then the nick name in Google is compared. In this case, preferredName in eDirectory is mapped to NickNames in Google. Again using the variable with the proposed email address calculated a moment ago.

If we match, then we merge, which has the usual set of issues to be concerned with. This is where the Filter setting about merge authority comes into play. I discussed merge authority in part 7 of my series about things beginners to Identity Manager need to know:

Part 7, about Merge Authority is available in this article: Common Mistakes Newcomers to IDM Make – Part 7

The rest of the series is available in these articles:

That’s about it for this article. Next article I will start working through the Creation Policy set, which is where we go, if the Match fails. What do we need before we allow the driver to create the object.

VN:F [1.9.22_1171]
Rating: 5.0/5 (1 vote cast)
Walking through the IDM 4 Google Apps Driver - Part 2, 5.0 out of 5 based on 1 rating
Series Navigation<< Walking through the IDM 4 Google Apps Driver – Part 1Walking through the IDM 4 Google Apps Driver – Part 3 >>

Tags: ,
Categories: Identity Manager, Technical Solutions

Disclaimer: As with everything else at NetIQ Cool Solutions, this content is definitely not supported by NetIQ, so Customer Support will not be able to help you if it has any adverse effect on your environment.  It just worked for at least one person, and perhaps it will be useful for you too.  Be sure to test in a non-production environment.

Comment