Tuesday, July 22, 2008

 

OAM Identity XML (IDXML) via XMLHttpRequest

It makes sense that the ideal HTTP Client for IDXML processing is the authenticated user's browser. After all, it already has the ObSSOCookie.

JQuery is the Javascript library of choice for all my client work lately. You can see why in the following example of processing an IDXML request via Javascript straight from the client. The use cases for this capability are endless.

This is the proverbial 'tip of the iceberg' in utilizing OAM Identity in a modern web development context. The end result: Perfectable user experiences based on data and services made available and secured through OAM's web based configuration tools. It's a powerful combination.

Lets take a simple create user workflow request and turn out a simple Javascript templating function to build the string for us:

getSoap = function(data){
var dat = [];
dat[dat.length] = '<?xml version="1.0" encoding="UTF-8"?>';
dat[dat.length] = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas-xmlsoap.org/soap/envelope/" xmlns:oblix="http://www.oblix.com">';
dat[dat.length] = '<SOAP-ENV:Body>';
dat[dat.length] = '<oblix:request function="workflowSaveCreateProfile" version="NPWSDL1.0">';
dat[dat.length] = '<oblix:params>';
dat[dat.length] = '<oblix:ObWorkflowName>obworkflowid=672fcf2e9c5946a8b5b225b349acd46b,obcontainerId=workflowDefinitions,OU=Oblix,OU=apps,DC=company,DC=com</oblix:ObWorkflowName>';
dat[dat.length] = '<oblix:ObDomainName>OU=people,DC=company,DC=com</oblix:ObDomainName>';
dat[dat.length] = '<oblix:noOfFields>5</oblix:noOfFields>';
dat[dat.length] = '<AttributeParams xmlns="http://www.oblix.com/">';
dat[dat.length] = '<GenericAttribute>';
dat[dat.length] = '<AttrName>uid</AttrName>';
dat[dat.length] = '<AttrNewValue>'+data.uid+'</AttrNewValue>';
dat[dat.length] = '<AttrOperation>ADD</AttrOperation>';
dat[dat.length] = '</GenericAttribute>';
dat[dat.length] = '<GenericAttribute>';
dat[dat.length] = '<AttrName>cn</AttrName>';
dat[dat.length] = '<AttrNewValue>'+data.cn+'</AttrNewValue>';
dat[dat.length] = '<AttrOperation>ADD</AttrOperation>';
dat[dat.length] = '</GenericAttribute>';
dat[dat.length] = '<GenericAttribute>';
dat[dat.length] = '<AttrName>mail</AttrName>';
dat[dat.length] = '<AttrNewValue>'+data.mail+'</AttrNewValue>';
dat[dat.length] = '<AttrOperation>ADD</AttrOperation>';
dat[dat.length] = '</GenericAttribute>';
dat[dat.length] = '<GenericAttribute>';
dat[dat.length] = '<AttrName>givenName</AttrName>';
dat[dat.length] = '<AttrNewValue>'+data.givenName+'</AttrNewValue>';
dat[dat.length] = '<AttrOperation>ADD</AttrOperation>';
dat[dat.length] = '</GenericAttribute>';
dat[dat.length] = '<GenericAttribute>';
dat[dat.length] = '<AttrName>sn</AttrName>';
dat[dat.length] = '<AttrNewValue>'+data.sn+'</AttrNewValue>';
dat[dat.length] = '<AttrOperation>ADD</AttrOperation>';
dat[dat.length] = '</GenericAttribute>';
dat[dat.length] = '</AttributeParams>';
dat[dat.length] = '<oblix:obactorcomment>IDXML from browser via Javascrip</oblix:obactorcomment>';
dat[dat.length] = '</oblix:params>';
dat[dat.length] = '</oblix:request>';
dat[dat.length] = '</SOAP-ENV:Body>';
dat[dat.length] = '</SOAP-ENV:Envelope>';

return dat.join("");
};


Then, if we prep a little data object with values (presumably pulled from the user interface):


var userdata = {
uid:"marmil",
cn:"Mark Miller",
mail:"mark[at]nulli.com",
givenName:"Mark",
sn:"Miller"
};


I can call my template and consider my soap envelope ready to go:


var createUserSoapRequest = getSoap(userdata);


All over but the sending (and response handling):


// process the request
$.ajax({
type: "POST",
dataType:'xml',
url: "/identity/oblix/apps/userservcenter/bin/userservcenter.cgi",
data: createUserSoapRequest,
contentType:"text/xml",
processData:false,
success: function(idxmlResponse){
// crude
alert(idxmlResponse);

// better
$("ObConfirmation",idxmlResponse).find("ObValue").each(function(i,o){
alert($(o).text());
});

// in the real world, employ dom trickery to keep the user oriented...
}
});



Cool, no?

Labels:


Comments:
For the user experience to be anything even remotely like perfectable IDXML would need to be a lot less broken than it now.

For starters it seriously needs well defined error reporting, using some kind of error codes, so it would be possible to tell the user what went wrong.
 
In most cases this information is available in the response or can be made available (thinking setting response text in PPP plugins, etc.). Where have you been burned?
 
We have yet to be completely burned, as we have been able to work around all the problems we have encountered.

It is true that it is possible to set the response text from plugins, but we do not use plugins for all operations. Besides, this is 2008, designing a web service to be easy for developers to use is not an arcane art, and Oracle has blown it so badly that it is not even funny. Their is the rather convoluted message formats. No less than two wsdl files pr. operation, making it rather hard to effectively use xml bindings to write generic code to access errors. Then we get the joy of a response format that mixes data and presentation (!). And finally their is an error reporting strategy consisting of writing a text message, instead of a much more usefull welldefined error code.
 
"Besides, this is 2008"

Ah therein lies the problem... IDXML is too old for a such a modern expectation ;)

Fairness to Oracle - they inherited a weak web services wrapper around the IDXML stuff (which was never perfect).

Though some customers might, we never use the web services stuff (except to sort out the post 6.5 syntax sometimes) and always run with direct construction of the soap envelopes. Have you played with the request mode options dataonly and silent? You're right - the web services wrapping are completely non descriptive.

What we've been excited about though is the use of jQuery to process IDXML from the browser directly. We've also been using the XSL environment to output JSON format data from the identity system.

Puts OAM at it's best to leave it in charge of security and core services and offload the presentation to the more capable browser environment.

See if you can give it a try and let me know what you think.

Thanks for your comments.
 
Mark,
Thanks for all the great info in your blog. It's the best collection of OAM tips and tricks that I've seen. I have a problem that I am trying to solve that I was hoping to solve in a similar way...but it has a little twist to it. The high level problem is that I need to customize the Self-Registration functionality. We are using CAC cards to authenticate. If the user is not in the LDAP, we need to self-register them. We do not, however, want to trust the user to fill in the info properly and instead want to grab it from the x509 certificate and automatically make a call to IdentityXML to kick off the workflow for self registering. I haven't, however, figured out a slick way to make this happen without leaving Oracle's control and not have to ask for the cert again. Is there anywhere in the bowels of Oracle, a servlet, xsl, etc... that I could modify to be able to make this a little more seamless and not have to write a custom servlet to obtain the cert and then call IdXML externally? Hopefully I'm making some sense. Any guidance would be much appreciated. Thanks, Dave
 
Dave,

You're breaking ground we haven't covered based on your description.

My guess is that your answer may be in the form of a custom authentication plugin where the existence of the user (or not) provides the fork in the road that you then use to make an HTTP SOAP request filled with data obtained from the cert. I trust you are acquainted with the OAM Developer's Guide. Sounds like a cool adventure. All the best with it.

Cheers, Mark
 
Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?