Retrieving GCVs within IDM Form Script

0 Likes
over 6 years ago
GCVs are immensely valuable components within an IDM solution. Use of GCVs can increase the configurability and reduce the amount of code customization required to both reproduce a solution, to move it between deployment stages (I.e, dev to test to production), and maximizes agility in case a solution's name space or other factors need to be altered.

There are three main components to IDM solutions:


  • The Metadirectory Engine

  • The Workflow Engine

  • Form Script


GCVs have been available within the IDM engine since 2.0, and were added to the workflow engine as well in a welcome enhancement. However one place GCVs remain inaccessible is within the form script. Until now.

Implementation


 
The components that need to be defined for this solution to work include:


  • DAL Entity Definitions

  • DAL Query

  • Form Script Libraries

  • Global (form-wide) Variables

  • An “onload” event handler in the first field in the form.


DAL


 
Three new entities must be added to the DAL to support this solution:



Key

Class Name

Attributes



Driver

DirXML-Driver



  • DirXML-ConfigValues

  • DirXML-JavaModule

  • DirXML-Policies

  • GUID





DriverSet

DirXML-DriverSet



  • DirXML-ConfigValues

  • DirXML-Policies





GCV

DirXML-GlobalConfigDef



  • DirXML-ConfigValues






Additionally, a query named FindUserApp must be defined, which searches for any Driver where the DirXML-JavaModule equals “com.novell.idm.driver.ComposerDriverShim”

About Security


 
One important note: In order for GCVs to be readable in form script, you need to make them readable in form script. In other words, you may need to alter your ACLs to allow mere mortals to read the IDM system configuration. If there is sensitive information in your GCVs, we recommend that you create a separate GCV object with the data that you need to publish and only expose that object to the user population.

In order for the script to locate the User Application Driver, it relies on the query of DirXML-JavaModule, so that attribute will need to be searchable. The DirXML-Policies attribute is used to locate GCV objects, and the DirXML-ConfigValues attributes contains the XML which stores the GCV data itself.

Scripts


 
Several bits of form script need to be added in order to access GCVs. For re-usability purposes, I have divided these into three separate scripts:

Script #1 provides XML libraries

function xmlParse(XML)
{
var oParser = new DOMParser();
var oDOM = oParser.parseFromString(XML, "text/xml");
return oDOM;
}
function xmlSetText(DOM, elementName, value)
{
var textNode = DOM.getElementsByTagName("value")[0].childNodes[0]
textNode.nodeValue = value;
}
function xmlSetAttribute(DOM, elementName, attributeName, value)
{
var attrNode = DOM.getElementsByTagName(elementName)[0].getAttributeNode(attributeName);
attrNode.nodeValue = value;
}
function getXMLResponse(form,field,xmlhttp,url,domRequest,callbackFunction)
{
txtRequest = new XMLSerializer().serializeToString(domRequest.documentElement);
xmlhttp.open("POST",url,true);
xmlhttp.setRequestHeader("Content-type", "text/xml");
xmlhttp.send(txtRequest);
xmlhttp.onreadystatechange= callbackFunction;
}
function xmlGetText(DOM, elementName)
{
var textNode = DOM.getElementsByTagName("value")[0].childNodes[0]
return textNode.nodeValue;
}
function xmlGetAttribute(DOM, elementName, attributeName)
{
var attrNode = DOM.getElementsByTagName(elementName)[0].getAttributeNode(attributeName);
return attrNode.nodeValue;
}
function xmlGetElementByAttribute(DOM, elementName, attributeName, value)
{
var textNodes = DOM.getElementsByTagName(elementName)
//Form.showDebugMsg("Found " textNodes.length.toString() " GCVs")
for (var i = 0; i < textNodes.length; i )
{
var attrNode = textNodes[i].getAttributeNode(attributeName);
if (attrNode.nodeValue == value)
{
return textNodes[i]
}
}
return "";
}

 

Script #2 provides some basic parsing for DN conversions between formats:

function ndap2ldap(ndapName)
{
var parts = ndapName.split("\\");
var ldapName = "";
for (var i = 0; i < parts.length; i )
{
ldapName = parts[i] "," ldapName;
}
return ldapName.substring(0,ldapName.length-1);
}
function ldap2ndap(ldapName)
{
var parts = ldapName.split(",");
var ndapName = "";
for (var i = 0; i < parts.length; i )
{
ndapName = parts[i].split("=")[1] "\\" ndapName;
}
return ndapName.substring(0,ndapName.length-1);
}
function ldap_parent_DN(DN)
{
var secs = DN.split(",")
return DN.substring(secs[0].length 1);
}
/* error checking - tests to see if a variable is undefined */
function undef(v)
{
return (typeof(v) == "undefined") || (null == v) || (v.toString() == "") ;
}

 

The main GCV code is in script #3

function UA_DN(IDVault)
{
var Q = IDVault.globalQuery(null, "FindUserApp")
return Q[0].toString();
}
function cacheAllGCVs(IDVault)
{
//statically configured GCVs
GCV["dirxml.auto.treename"]="ACMEDEV"
//get other base GCVs
GCV["dirxml.auto.driverdn.ldap"] = UA_DN(IDVault);
GCV["dirxml.auto.driverdn"] = ldap2ndap(GCV["dirxml.auto.driverdn.ldap"]);
GCV["dirxml.auto.driverguid"] = IDVault.get(null,GCV["dirxml.auto.driverdn"],"Driver","GUID");
GCV["dirxml.auto.driverset.ldap"] = ldap_parent_DN(GCV["dirxml.auto.driverdn.ldap"]);
GCV["dirxml.auto.driverset"] = ldap2ndap(GCV["dirxml.auto.driverset.ldap"]);
// get GCVs from Driver Set
cacheGCV(IDVault, "DriverSet",GCV["dirxml.auto.driverset.ldap"])
// get GCVs from linked Driver Set GCV objects
cacheLinkedGCVs(IDVault, IDVault.get(null,GCV["dirxml.auto.driverset.ldap"],"DriverSet","DirXML-Policies"))
// get GCVs from Driver
cacheGCV(IDVault, "Driver",GCV["dirxml.auto.driverdn.ldap"])
// get GCVs from linked Driver GCV objects
cacheLinkedGCVs(IDVault.get(null,GCV["dirxml.auto.driverdn.ldap"],"Driver","DirXML-Policies"))
}
function cacheLinkedGCVs(IDVault, list)
{
if (!undef(list))
{
for (var i=0; i < list.length; i )
{
var values = list[i].split("#");
if (values[2]=="14")
{
cacheGCV(IDVault, "GCV", values[0])
}
}
}
}
function cacheGCV(IDVault,typeName,dn)
{
var xmlText = IDVault.get(null, dn, typeName, "DirXML-ConfigValues")
if (!undef(xmlText))
{
xmlGCV = xmlParse(xmlText.toString());
var defs = xmlGCV.getElementsByTagName("definition")
for (var i=0; i < defs.length; i )
{
var xmlAttrName=defs[i].getAttributeNode("name").nodeValue;
var xmlValue = defs[i].getElementsByTagName("value")[0].childNodes[0].nodeValue;
// Form.showDebugMsg("GCV[\"" xmlAttrName "\"] = \"" xmlValue "\"");
GCV[xmlAttrName] = xmlValue;
}
}
}
function getGCV(gcvName)
{
var definitionNode = xmlGetElementByAttribute(xmlGCV, "definition", "name", gcvName)
var valueNode = definitionNode.getElementsByTagName("value")
return valueNode[0].childNodes[0].nodeValue;
}

 

In the first field's onload event handler, add the following code:
cacheAllGCVs(IDVault);

 

Finally, under the “Events” tab, in the global form onload script, add the following code:
/** global objects **/ 

xmlGCV = new Object(); // Cache to store GCV data

GCV = new Array();

function createXMLHttpRequest() {

try { return new XMLHttpRequest(); } catch(e) {}

try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}

form.alert("XMLHttpRequest not supported by this browser");

return null;

}

xmlhttp = createXMLHttpRequest();


 

Using GCVs Within Your Form Script


 
To reference the data within a GCV, simply use the GCV array object, specifying the index as the name of the GCV. For example:

var rolesDN = GCV["gcv.driverset.rolesDN"]


Other Considerations



 
Limitations, additions and other care and feeding:

  • Not all default GCVs (dirxml.auto.*) are supported.

  • Additional default GCVs, when used to calculate the standard ones, are stored. These are generally LDAP versions of the same GCV which use the same name with “.ldap” appended.

  • The tree name is not currently accessible from the DAL, so to support dirxml.auto.treename you need to edit the script to set the correct default tree name.

  • The initialization of the GCV cache may cause a brief delay loading your form. You can reduce this delay by editing the function cacheGCVs to limit the number of GCVs from Form Script objects it reads to the ones you specifically need.


Conclusion


 
The ability to access GCVs easily from within your form script closes an important gap in the configurability of NetIQ Identity Manager. This is the last area of IDM where configuration data was separate from all the other components. Now, one or more GCVs can be defined within your solution and can carry configuration information which is used by the Metadirectory Engine, the Workflow Engine and now the Form Engine, simplifying migrations, and making solutions more re-usable.

 

Labels:

How To-Best Practice
Comment List
Anonymous
Related Discussions
Recommended