Monday, August 5, 2013

Creating a Custom OVD Plugin

1. Introduction

In a recent engagement, I worked with a customer that had a business requirement where they needed to create and expose to their application two computed LDAP attributes, based on the value of an existing attribute.

For instance, let’s say the original attribute is "myCorpID" and its value could be something like "23451588-IT Specialist".

The requirement is to have two new defined attributes: "jobCode" and "jobTitle", that would have values "jobCode=23451588" and "jobTitle=IT Specialist".

To achieve this we would use OVD, which was already in place to virtualize different LDAP directoriess and databases.

OVD does not come with functionality out of the box to implement this requirement but does allow you to write custom plugins, where you can extend the capabilities of OVD to include requirements such as the one my customer had.

This post shows how to develop a custom OVD plug-in.

This plug-in reads a LDAP Object’s attribute value, splits the value in two, using a delimiter, and creates two new attributes with values assigned from the split operation.

Though this is a very simple requirement, and in fact my customer requirements were more complex than that, it can be used as a starting point to develop different use-case needs.

This plug-in is designed to work with a LDAP Adapter, and will run it’s logic for each LDAP "get" operation, before handing the result back to OVD.

The plug-in is flexible enough to work with any LDAP "objectClass" that has an attribute of String data type with a pattern delimiter that can be split in two.

2. Creating the Custom OVD Plug-in

a. Create a Standard Java Project in your preferred IDE. For this example, Eclipse is used.

b. Add vde.jar, ovdcommon.jar and asn1c.jar to your project's build path. These files are located in $ORACLE_HOME/ovd/jlib. I created Variable in Eclipse to avoid those libs to be packaged with the final JAR.

c. Create a package and a new Class, name it what you will and make your class extend "com.octetstring.vde.chain.BasePlugin".

d. In this class we will create the following properties:

String jobCode = null;
String jobTitle = null;
String delimiter = null;
String originalAttribute = null;
String objectclass = null;

Those properties will be configurable through OVD console, this way our plugin is flexible and can accept different configurations at runtime. More on that later…

e. Implement just the methods that you want the plug-in to run its logic. In this example we implemented the "postSearchEntry", which is called after each "get" call to the LDAP. In this way, we can manipulate the result from the LDAP, before handing it back to OVD. Besides that, we will also implement "available()" and "init()" methods. The first tells OVD if this plugin is available for the current Chain, which for simplicity sake, we will always return true. The latter, we will use to read and initialize our variables configured in OVD console.

f. Create a new (or edit existing one) MANIFEST.MF file in the META-INF folder. It should contains the following information:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 1.6.0_41-b02 (Sun Microsystems Inc.)
vde-package-name: SplitLDAPAttribute
vde-package-ops-add: false
vde-package-ops-delete: false
vde-package-ops-bind: false
vde-package-ops-modify: false
vde-package-ops-rename: false
vde-package-ops-get: true
vde-package-description: Splits a configured LDAP attribute into two other attributes using a separator character. 
vde-package-type: 0
vde-package-version: 0
vde-package-param-jobCode-description: The first attribute that will be created as the result of the split.
vde-package-param-jobTitle-description: The second attribute that will be created as the result of the split.
vde-package-param-delimiter-description: The separator character that will split the LDAP attribute
vde-package-param-originalAttribute-description: The attribute that will be split into two new attributes.
vde-package-param-objectclass-description: The ObjectClass which the filter should run the split operation

Note that the properties described in the MANIFEST file, corresponds to the properties we created in our class and that we want to configure in runtime in OVD console. We have also declared which methods are available and implemented in this plugin and other description metadata that will be available in OVD console.

3. The init() method:

    public void init(PluginInit initParams, String name) throws ChainException {
        if (initParams.containsKey("originalAttribute")) {
        originalAttribute = initParams.get("originalAttribute");
        if (initParams.containsKey("jobCode")) {
        jobCode = initParams.get("jobCode");
        if (initParams.containsKey("jobTitle")) {
        jobTitle = initParams.get("jobTitle");
        if (initParams.containsKey("delimiter")) {
        delimiter = initParams.get("delimiter");
        if (initParams.containsKey("objectclass")) {
        objectclass = initParams.get("objectclass");

4. postSearchEntry() method:

public void postSearchEntry(Chain chain, Credentials creds,
            Vector returnAttribs, Filter filter, Int8 scope,
            DirectoryString base, Entry entry, ChainEntrySet entrySet)
            throws ChainException, DirectoryException {

//Initialize ObjectClassCheck variable
boolean isObjectClassCheck = false;

//Initialize The Original Attribute variable that will be split
        DirectoryString splitAttribute = new DirectoryString(originalAttribute);
        //Initialize the ObjectClass Attribute variable
        DirectoryString objectClassAttribute = new DirectoryString("objectClass");
        //Checks if the current entry has the required objectclass
        if(entry.containsKey(objectClassAttribute)) {
       Vector objClasses = entry.get(objectClassAttribute);
       for(int i = 0; i < objClasses.size(); i++) {
        DirectoryString oc = (DirectoryString) objClasses.get(i);
        //If the current entry objectclass matches the configured by the 
        //plugin it will be processed
        isObjectClassCheck = true;

        //If the current entry has the Attribute that will be split and
        //if it is of the configured objectclass we proceed to split the attribute
        if (entry.containsKey(splitAttribute) && isObjectClassCheck) {
        //Gets the Attribute configured to be split
            DirectoryString splitAttributeValue = (DirectoryString) entry.get(splitAttribute).get(0);
            //Splits the Attribute value
            String[] splittedValues = splitAttributeValue.toString().split(delimiter);

            //Checks if the split result has at least 2 elements
            if (splittedValues != null && splittedValues.length > 1) {
            //Creates Custom Attributes and set their values
                DirectoryString jobCodeAttr = new DirectoryString(jobCode);
                Vector jobCodeVec = new Vector();
                jobCodeVec.add(new DirectoryString(splittedValues[0]));
                DirectoryString jobTitleAttr = new DirectoryString(jobTitle);
Vector jobTitleVec = new Vector();
jobTitleVec.add(new DirectoryString(splittedValues[1]));         
                //Adds the custom Attributes to the current entry
            entry.put(jobCodeAttr, jobCodeVec);
            entry.put(jobTitleAttr, jobTitleVec);

        // calls the next plug-in in the chain (or comment out if a handler)
        chain.nextPostSearchEntry(creds, returnAttribs, filter, scope, base, entry, entrySet);

5. Creating the JAR file.

At this point all we need to do is package everything as a JAR file. Use your IDE’s or command line methods to package your project in a JAR file, but take special care to include the MANIFEST.MF we created in the resulting JAR.

6. Installing the plug-in

a. Go to OVD Console
b. Go to Advanced Tab, Library section

c. Click on the "Upload New Library" button, choose your JAR file and click OK

d. Refresh the view and your plug-in should appear on the list

7. Configuring the plug-in

a. Go to "Adapter" tab, choose the adapter you want to attach the plug-in to and click on "Plug-ins" tab

b. Click on "Create plug-in" button; give it a name, and select the plug-in class you created from the list.

c. Click on create parameter, and set the parameter values for each of the required parameters. Those parameters will be used by the plug-in logic to perform the attributes split.

d. In our example, those are the attributes used by our plug-in:

The example Plug-in has the following configurable parameters:

This is the object class the plug-in will only be invoked on.
This is a new attribute the plug-in will create on the fly which will be populated with the first value from the split operation.  The name of the resulting attribute can be anything you want including an existing attribute.  If there is an existing LDAP attribute, the original attribute value will be replaced by the value the plug-in gets.
This is a new attribute the plug-in will create on the fly which will be populated with the second value from the split operation.  The name of the attribute can be anything you want including an existing attribute.  If there is an existing LDAP attribute, the original attribute value will be replaced by the value the plug-in gets.
This is the character used to delimit the value.  For example if the attribute value is 23984839-Specialist, the hyphen “-“ could be used as the delimiter to split the value.
This is the original LDAP attribute the plug-in will get the original value from.

e. Select the "Get" operation from the "Select Operation" drop-down list, choose the plug-in you created and click "Apply" button.

f. Click "Apply" to save the configuration for this adapter’s plug-in.

8. Testing the plug-in

a. Go to the “Data Browser” tab, drill down to the data structure exposed by your adapter, and select one of the groups.
b. In the right side of the screen, click on the “Views” button and Select “Show All”.

c. Inspect the object’s properties and find the newly created properties from the original property chosen to be split.

The same can be verified by external LDAP clients, like Apache Directory Studio.

The properties can also available in a Join view, where the LDAP adapter is joined with a Database Adapter, to include additional information coming from a database.

9. Uninstalling the Plug-in

a. Stop OVD process and ODSM server
b. Remove the JAR file from $ORACLE_INSTANCE/ovd/ovd1/ (do this for each OVD instance).
c. Restart ODSM and OVD
d. Remove the plug-in from the Adapter Plug-in Tab.

10. Reference

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.