Service Provisioning Markup Language (SPML) is an XML-based framework, being developed by
OASIS, for exchanging user, resource and service provisioning information between cooperating organizations. There are currently two versions of the specification,
version 1.0 (SPMLv1) released in 2003 and
version 2.0 (SPMLv2) released in 2006.
Sun Identity Manager (IdM) is the Sun Identity product and implements SPMLv1 since I know it and SPMLv2 support has been being adopted throughout versions. IdM 7.x and 8.0 versions do not support search (capability to search objects), reference (capability to reference objects from other objects) and updates (a kind of changelog track capability) in their SPMLv2 implementation. The actual 8.1 version released in 2009 added search support for version 2.0. Looking at the client side there is a open source implementation called
openspml for both versions in java language.
SPML is usually an important part in any identity deployment with IdM becuase it always covers some of the user cases. In fact this framework is necessary in any provision flow triggered by another application. A white pages application inside the company that let employees to change their passwords or any other data must send changes to the Identity software via SPML. Intranet webapp in which a employee can request a mail or any other role or account for him or other mate has to use again SPML to start a provision flow. Although IdM end user pages can do all this work there are usually previous applications which customers want to not deprecate or a corporate portal they want to use. Here is where SPML rules.
Before IdM 8.1 was released I always used SPMLv1 to integrate this external applications into the new identity solution (the lack of search capability was decisive). But now, with the new 8.1 version, search capability has come into SPMLv2 and a move forward seems necessary. The main risk in the switch is that SPMLv1 has some extended requests: deleteUser, disableUser and enableUser, resetUserPassword and changeUserPassword, launchProcess, listResourcebjects and runForm. Some of them are not covered by any SPMLv2 capability (launchProcess and runForm) and for me launchProcess is a no-go. The SPMLv1 launchProcess extended request is a way to execute any generic IdM workflow and it can resolve any SPML limitation. For example, if the customer wants that managers can approve or reject provision requests using another existing java/web application there is no SPML standard way to do it, and, in this cases, launchProcess goes into action.
Some free time this week let me test this issue and try to extend SPMLv2 IdM implementation with a custom LaunchProcess request. The idea was simple: add SPMLv1 launchProcess into SPMLv2. In this proof of concept (PoC) I just create a new LaunchProcessRequest and LaunchProcessResponse classes in the client part.
- LaunchProcessRequest. This request has a PSO which represents the workflow to execute and a generic extensible data property. The data is a bunch of DSML attributes that will be passed as inputs to the workflow.
<complexType name="LaunchProcessRequestType">
<complexContent>
<extension base="spml:RequestType">
<sequence>
<element name="psoID" type="spml:PSOIdentifierType" />
<element name="data" type="spml:ExtensibleType" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
- LaunchProcessResponse. The launchProcess response consists in the usual outputs (status, error code, error messages,...) and again a extensible data property that has all the outputs of the workflow as DSML attributes.
<complexType name="LaunchProcessResponseType">
<complexContent>
<extension base="spml:ResponseType">
<sequence>
<element name="data" type="spml:ExtensibleType" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
This class (with some others) are in the org.openspml.v2.msg.spml package. Previously the name of this package was org.openspml.v2.msg.spmlextended but objects inside this package can't be unmarshalled. The openspml implementation of SPMLv2 uses org.openspml.v2.util.xml.ObjectFactory class to link namespaces in XML with java classes. This class has the mappings hardcoded (maybe I just didn't know how to add a link between urn:oasis:names:tc:SPML:2:0:extended:launchProcessRequest namespace and org.openspml.v2.msg.spmlextended package or simply I forgot something else). Because of that the package was renamed to this new package which is the default for any unknown namespace. This package exists in openspml and it contains classes so my class names were chosen to be different to any standard pre-existing class.
Server implementation consists in a executor class which receives the LaunchProcesRequest object and executes the specified workflow (in the PSO property) with the given input arguments (data extensible DSML attributes). After execution results are set into LaunchRequestResponse object. If the workflow is executed without errors (WavesetResult.hasError method is false) the status is set to SUCCESS and all the data ResultActions are added into data extensible. If the execution has errors, status is FAILURE, error code is set to CUSTOM_ERROR, all error messages are set and data ResultActions added into data in the same way. If some exception is thrown, status is FAILURE, code CUSTOM_ERROR, and exception message is added to error messages (no data is added cos it is not available). This class is LaunchRequestExecutor under com.sun.idm.rpc.spml2.extended package.
Finally a short client code is presented.
SessionAwareSpml2Client client = null;
try {
// config
String url = "http://192.168.122.11:8080/idm/servlet/openspml2";
String user = "configurator";
String password = "configurator";
// start client doing the login
client = new SessionAwareSpml2Client(url);
Response resLogin = client.login(user, password);
// generate a launchprocess request
LaunchProcessRequest req = new LaunchProcessRequest();
req.setExecutionMode(ExecutionMode.SYNCHRONOUS);
req.setPsoID(new PSOIdentifier("Sample Workflow", null, null));
Extensible data = new Extensible();
data.addOpenContentElement(new DSMLAttr("par1", "value1"));
data.addOpenContentElement(new DSMLAttr("par2",
new DSMLValue[] {new DSMLValue("par2-val1"), new DSMLValue("par2-val2")}));
req.setData(data);
Response resLaunch = client.send(req);
} catch (Spml2ExceptionWithResponse e) {
System.err.println("Error inside workflow execution but response given");
Response resLaunch = e.getResponse();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (client != null) {
try {client.logout();} catch(Exception e) {}
}
}
The resulting netbeans 6.8 project is
here and the steps to run it are the following:
- Install Sun Identity Manager 8.1 (this is the version I used but newer versions are supposed to work too).
- Add inside the deployed idm.war the launchPrecess.jar of this project (in WEB-INF/lib directory).
- Add the spml2.xml to activate SPMLv2 in IdM. Go to IdM console (http://server:port/idm) and in Configure -> Import Exchange File select the spml2.xml in the extras directory of the project. The spml2.xml has been modified to include the new LaunchProcess capability and its executor (original IdM 8.1 file was backed up in spml2.xml.ORIG in the same directory).
- Import in the same way the two workflow examples in the extras directory:
- Sample Workflow: Just a workflow that returns some data.
- Sample Error Workflow: Workflow which generates error response.
- Open LaunchProcess project with Netbeans.
- Execute the TestLaunchProcess class (you can change the workflow name between "Sample Workflow" and "Sample Error Workflow" in order to execute one workflow or the other).
Just remember this is a PoC. Maybe the decisions of what to pass and receive in requests/responses, how map workflow inputs and outputs or any other task could be done in a different way but...
Enjoy it.
Comments