Many companies have implemented access management, or Web Single Sign-on, technologies to secure their web applications. Most implementations utilize a web / application server plugin to externalize security, with session management using opaque authentication tokens persisted in browers cookies.
In many environments a SSO plug-in, or agent, is installed to protect a web service. In these cases it’s often desirable, if not mandatory, to send token cookies in the context of a SOAP over HTTP invocation from a web service client. This blog has an excellent write-up for doing just that using an Apache Axis Handler. However, its not always feasible to externally configure the handler chain using the XML client descriptor for Axis. Furthermore, when executing in a threaded environment where cookie names and values are dynamic and per-thread differences, providing accessor methods to retrieve thread local data can be painful. Luckily it is possible to use dynamic configuration of an Axis client to meet these requirements:
Start off by creating a BasicHandler. This class functions as a simple container for the cookie name and value.
class CookieHandler extends BasicHandler { private String cookieName; private String cookieValue; public CookieHandler(String cookieName, String cookieValue) { this.cookieName = cookieName; this.cookieValue = cookieValue; } public void invoke(MessageContext context) throws AxisFault { context.setProperty(HTTPConstants.HEADER_COOKIE, cookieName + “=” + cookieValue); } }
Next, create method that will prepare and return an Axis EngineConfiguration. Initialize the CookieHandler and make sure to add it to the request chain’s handler list.
private EngineConfiguration createCookieTokenConfig(String cookieName, String cookieValue) throws Exception { SimpleProvider clientConfig=new SimpleProvider(); Handler cookieHandler= (Handler) new CookieHandler(cookieName, cookieValue); SimpleChain reqHandler=new SimpleChain(); SimpleChain respHandler=new SimpleChain(); // add the handler to the request reqHandler.addHandler(cookieHandler); // add the handler to the response Handler pivot=(Handler)new HTTPSender(); Handler transport=new SimpleTargetedChain(reqHandler, pivot, respHandler); clientConfig.deployTransport( HTTPTransport.DEFAULT_TRANSPORT_NAME,transport); return clientConfig; }
Finally, a convenience method can return a new instance of the binding with a prepared engine.
public XYZBindingStub getCookieTokenBinding(String cookieName, String cookieValue) {
XYZBindingStub binding;
try {
XYZServiceLocator loc = new XYZServiceLocator();
EngineConfiguration clientConfig=createCookieTokenConfig(cookieName, cookieValue);
loc.setEngineConfiguration(clientConfig);
loc.setEngine(new AxisClient(clientConfig));
binding = (XYZSoapBindingStub) loc.getIdBus();
} catch (javax.xml.rpc.ServiceException jre) {
if (jre.getLinkedCause()!=null)
jre.getLinkedCause().printStackTrace();
throw new junit.framework.AssertionFailedError("JAX-RPC ServiceException caught: " + jre);
}
binding.setTimeout(60000);
// set true to instruct axis client to send cookies
binding.setMaintainSession(true);
return binding;
}
Now, its as simple as calling a single method to obtain a binding that will issue the desired cookie.
XYZBindingStub stub = getCookieTokenBinding(“TokenName”, “TokenValue”); stub.method(“a”, “b”, “c”);
Replace “TokenName” and “TokenValue” with values appropriate for your company’s flavor of access management system (COREid, Siteminder, etc…) and you have a viable method of authenticating your Axis-based web service client to Web SSO protected services.