Creating a Dynamic Group with Identity Manager

A dynamic group is not unlike any other LDAP group with but a few exceptions.  Its membership list is generated by an LDAP query rather than a direct DN assignment.  The power of a dynamic group within an IDM infrastructure, is that roles and entitlements can be granted to the dynamic group, and as a user’s attributes change, the entitlements can be granted or revoked based on the group membership rather than maintaining the entitlement on each individual user account.   As these entitlements can extend beyond the native directory of IDM, this can be a powerful tool for creating birthright roles and permissions across an enterprise.

In technical difference, a dynamic group, includes two additional attributes to perform this, dgIdentity and memberQuery.  The attribute, dgIdentity, is the DN of the user who will execute the LDAP query.  The attribute, memberQuery, is an Octet string that defines the LDAP query parameters.  It has a very particular format that is unique to each directory.

The following action executes the ECMAscript to build the memberQuery.  It requires the directory tree name, the context of the LDAP search, the attribute name to be used by the query, and the attribute value to build the LDAP query.

<do-add-dest-attr-value disabled="true" name="memberQuery">

      <arg-value type="octet">

            <token-xpath expression="es:buildDynamicGroupMemberQuery(string($dirxml.auto.treename), string($context), string($attrNameVar), string($attrValue))"/>

      </arg-value>

</do-add-dest-attr-value>

The following ECMAscripts, build the octet for the memberQuery attribute:

function buildDynamicGroupMemberQuery(tree, context, attrName, attrValue) {

  //00 00 00 00 02 00 00 00 2C 00 00 00

  //O = n o v e l l . t = g w a p p s t r e e

  //00 00 02 00 00 00 01 00 00 00

  //00 00 00 00 07 00 00 00 12 00 00 00

  //eDir-attr-name

  //00 00 00 00 10 00 00 00

  //eDir-attr-value

  //2A 00 00 00



  //Setup a default encoding if nothing is specified previously.

  encoding = System.getProperty("file.encoding")



  var byteData = new ByteArrayOutputStream();

  //outputStream.write(a);

  //outputStream.write(b);



  //Setting up the static part of the value.

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  byteData.write(2);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  //byteData.write(hex2dec("2C"));  //Some kind of byte offset for context/tree length.  For 18 characters (36 bytes), 2C (44) is shown.

  //Example: dc=org,t=gwappstree = 19 chars = 38 bytes = 40 offset = 0x28

  var offsetLength = ((3 + tree.length + context.length) * 2) + 2;

  byteData.write(offsetLength);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);



  //return new JString(Base64Codec.encode(new JString(str).getBytes(encoding)));



  //Add in the context, then the tree.

  //byteData.write(new JString(context).getBytes(encoding));

  var byteArray = spliceBytesWithNulls(new JString(context).getBytes(encoding));

  byteData.write(byteArray, 0, byteArray.length);

  byteData.write(hex2dec("2E"));

  byteData.write(0);

  byteData.write(hex2dec("74"));

  byteData.write(0);

  byteData.write(hex2dec("3D"));

  byteData.write(0);

  //byteData.write(new JString(tree).getBytes(encoding));

  var byteArray = spliceBytesWithNulls(new JString(tree).getBytes(encoding));

  byteData.write(byteArray, 0, byteArray.length);



  //Add in more static stuff.  The calculation seems to be unique to each directory.  Check the Octet values on the attribute from iMonitor.

  byteData.write(0);

  //byteData.write(0);

  //byteData.write(2);

  //byteData.write(0);

  //byteData.write(0);

  //byteData.write(0);

  //byteData.write(1);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  byteData.write(7);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  //byteData.write(hex2dec("12")); //Represents the number of bytes to offset for the attribute name.

  //'uniqueid' = 8 chars = 16 bytes = 18 = 0x12

  var offsetLength = ((attrName.length) * 2) + 2;

  byteData.write(offsetLength);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);



  //Add in the attribute name and, eventually, value.

  //byteData.write(new JString(attrName).getBytes(encoding));

  var byteArray = spliceBytesWithNulls(new JString(attrName).getBytes(encoding));

  byteData.write(byteArray, 0, byteArray.length);

  //Remove 2 of these for L as attr?

  //byteData.write(0);

  //byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  //byteData.write(hex2dec("10")); //Represents the number of bytes to offset for the value.

  //'test00*' = 7 chars = 14 bytes = 16 = 0x10

  var offsetLength = ((attrValue.length) * 2) + 2;

  byteData.write(offsetLength);

  byteData.write(0);

  byteData.write(0);

  byteData.write(0);

  //byteData.write(new JString(attrValue).getBytes(encoding));

  var byteArray = spliceBytesWithNulls(new JString(attrValue).getBytes(encoding));

  byteData.write(byteArray, 0, byteArray.length);

  byteData.write(0);

  byteData.write(0);



  //The value needs to have a number of bytes that is evenly disible by four, so make sure that happens padding with nulls.

  if(byteData.size() % 4) {

    byteData.write(0);

    byteData.write(0);

  }



  return new JString(Base64Codec.encode(byteData.toByteArray()));

}



/**

 * Function to put null bytes between other bytes in a byte array.

 */

function spliceBytesWithNulls(origByteArray) {

  var newByteArrayStream = new ByteArrayOutputStream();

  for(var ctr0 = 0; ctr0 < origByteArray.length; ++ctr0) {

    newByteArrayStream.write(origByteArray[ctr0]);

    newByteArrayStream.write(0);

  }

  return newByteArrayStream.toByteArray();

}

Adding these scripts and actions to your IDM drivers, will allow you to properly create the appropriate attributes for your dynamic group.  Good luck!