Saturday, January 30. 2010
OpenSSO Reverse Proxy Extension (Part I)
This time I have been playing with another Sun (AKA Oracle) product: OpenSSO. The Open Web Single Sign-On goal is to provide an extensible foundation for an identity services infrastructure in the public domain, facilitating single sign-on (SSO) for web applications hosted on web and application servers.
OpenSSO is a web framework. Single sign-on can be achieved in any web application with any programming language. Java SDK, J2EE agents, web agents and many other techniques or extensions are available. Nevertheless the applications need to explicitly use the framework and SSO cannot be accomplished in a transparent way. Little modifications are always needed to integrate legacy web applications.
Other SSO software products usually has a password replay feature, which consists in the ability to replay (resend) the password to this legacy applications. Historically this password replay absence has been an OpenSSO weakness against other products like IBM Tivoli Access Manager.
In the roadmap to OpenSSO 8.1 a Reverse Proxy with Password Replay was announced. This title was accompanied with a short description: "Our reverse proxy is being rewritten as a 100% Java proxy that also has the ability to capture and replay passwords for web applications not protected by your single sign-on solution. In short, this will allow Enterprise Single Sign-on (screen scraping) functionality for web applications. Applications that are not protected by OpenSSO can use password replay to do simple password capture and authentication". Theoretically this brand new feature is about to appear in the Express Build 9. As I am a little impatient I was searching throughout the code and I found a new extension called proxy three months ago. These days I have been testing the progress and I am going to present the first of a three posts series about this topic.
The reverse proxy solution is a Java Servlet application which uses Apache HttpCore components to build the necessary HTTP services between client and server. The servlet can have filters to change the information that travels from the client to the server and vice versa. There are filters to manage cookies (CookieFilter), headers (HeaderFilter) or to handle a Basic Authentication (HttpBasicAuthFilter). The other basic idea is a PasswordCredentialSource interface to get the username/password pair someway.
My first goal was to install a web server protected with Basic Authentication and use OpenSSO proxy extension to bypass the login with a static (hardcoded) username and password. All this stuff is a already done sample inside the proxy code (BasicAuthProxy.java).
First of all I checked out the proxy extension directory:
And I reorganized the directories putting all java code (core, samples and contribs) together:
Then I created a new Web Application project in Netbeans using Tomcat 6.0.20 as the web container. The web.xml was copied from the basic auth sample:
And Finally the java servlet was changed to point to my basic auth protected web server (installed in a KVM solaris box):
And it works. If we first access to the web the basic auth challenge pops up. But if we reopen the browser and access directely to the tomcat the web page appears with no login (proxy is silently logging me in).
In summary the proxy extension is clearly in a very first stage, the core is done but there is no integration with OpenSSO. In the next posts I will try to extend proxy with some OpenSSO functionality.
OpenSSO is a web framework. Single sign-on can be achieved in any web application with any programming language. Java SDK, J2EE agents, web agents and many other techniques or extensions are available. Nevertheless the applications need to explicitly use the framework and SSO cannot be accomplished in a transparent way. Little modifications are always needed to integrate legacy web applications.
Other SSO software products usually has a password replay feature, which consists in the ability to replay (resend) the password to this legacy applications. Historically this password replay absence has been an OpenSSO weakness against other products like IBM Tivoli Access Manager.
In the roadmap to OpenSSO 8.1 a Reverse Proxy with Password Replay was announced. This title was accompanied with a short description: "Our reverse proxy is being rewritten as a 100% Java proxy that also has the ability to capture and replay passwords for web applications not protected by your single sign-on solution. In short, this will allow Enterprise Single Sign-on (screen scraping) functionality for web applications. Applications that are not protected by OpenSSO can use password replay to do simple password capture and authentication". Theoretically this brand new feature is about to appear in the Express Build 9. As I am a little impatient I was searching throughout the code and I found a new extension called proxy three months ago. These days I have been testing the progress and I am going to present the first of a three posts series about this topic.
The reverse proxy solution is a Java Servlet application which uses Apache HttpCore components to build the necessary HTTP services between client and server. The servlet can have filters to change the information that travels from the client to the server and vice versa. There are filters to manage cookies (CookieFilter), headers (HeaderFilter) or to handle a Basic Authentication (HttpBasicAuthFilter). The other basic idea is a PasswordCredentialSource interface to get the username/password pair someway.
My first goal was to install a web server protected with Basic Authentication and use OpenSSO proxy extension to bypass the login with a static (hardcoded) username and password. All this stuff is a already done sample inside the proxy code (BasicAuthProxy.java).
First of all I checked out the proxy extension directory:
$ cvs -d :pserver:rickyepoderi@cvs.dev.java.net:/cvs login
$ cvs -d :pserver:rickyepoderi@cvs.dev.java.net:/cvs checkout opensso/extensions/proxy
And I reorganized the directories putting all java code (core, samples and contribs) together:
com/sun/identity/proxy/auth
com/sun/identity/proxy/contrib/sjsme
com/sun/identity/proxy/contrib/pmwiki
com/sun/identity/proxy/contrib/sjsce
com/sun/identity/proxy/contrib/mediawiki
com/sun/identity/proxy/http
com/sun/identity/proxy/util
com/sun/identity/proxy/handler
com/sun/identity/proxy/sample
com/sun/identity/proxy/sample/basicauth
com/sun/identity/proxy/sample/simple
com/sun/identity/proxy/io
com/sun/identity/proxy/servlet
com/sun/identity/proxy/filter
com/sun/identity/proxy/client
Then I created a new Web Application project in Netbeans using Tomcat 6.0.20 as the web container. The web.xml was copied from the basic auth sample:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Basic Auth Proxy</display-name>
<servlet>
<servlet-name>proxy</servlet-name>
<servlet-class>com.sun.identity.proxy.sample.basicauth.BasicAuthProxy</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>proxy</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
And Finally the java servlet was changed to point to my basic auth protected web server (installed in a KVM solaris box):
public class BasicAuthProxy extends SimpleProxyServlet{
@Override
public void init() throws ServletException {
init("http", "192.168.122.11", 81);
addFilter(new HttpBasicAuthFilter(
new StaticCredentialSource("ricky", "kiosko00"),
new TemporaryStorage()));
}
}
And it works. If we first access to the web the basic auth challenge pops up. But if we reopen the browser and access directely to the tomcat the web page appears with no login (proxy is silently logging me in).
In summary the proxy extension is clearly in a very first stage, the core is done but there is no integration with OpenSSO. In the next posts I will try to extend proxy with some OpenSSO functionality.
Friday, January 22. 2010
Extending IdM SPMLv2 with launchProcess
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.
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.
The resulting netbeans 6.8 project is here and the steps to run it are the following:
Enjoy it.
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).
Enjoy it.
« previous page
(Page 3 of 3, totaling 8 entries)
Comments